>假设我们用C写下以下字符常量:
'xFFFFAA'
它的数值是多少?
标准C99说:
- 字符常量的类型为
int
。 - 十六进制字符常量可以表示为
unsigned char
。 - 基本字符常量的值为非负值。
- 任何字符常量的值都适合
char
的范围。
此外:
signed char
的值范围包含在int
的值范围内。char
、unsigned char
和signed char
的大小(以位为单位)相同:1个字节。- 一个字节的大小由
CHAR_BIT
给出,其值至少为8。
假设我们有典型的情况 CHAR_BIT == 8
.
另外,让我们假设char
对我们来说是signed char
。
通过遵循规则:常量'\xFFFFAA'的类型为int
,但它的值可以用unsigned char
表示,尽管它的实际值适合char
。
根据这些规则,一个像"\xFF"的例子会给我们:
(int)(char)(unsigned char)'xFF' == -1
第一个转换unsigned char
来自"可以表示为无符号字符"要求。
第二个强制char
来自"值适合字符"的要求。
第 3 个转换int
来自"具有类型整数"要求。
但是,常数'xFFFFAA'
太大,不能"表示"为unsigned int
。
它的价值是什么?
我认为该值是(char)(0xFFFFAA % 256)
的结果,因为标准或多或少地说:
- 对于无符号整数类型,如果某个值大于该类型可以表示的最大 M,则该值是取余数模 M 后获得的值。
我得出这个结论是对的吗?
编辑 我被@KeithThompson说服了:他说,根据标准,一个大的十六进制字符常量是违反约束的。
所以,我会接受这个答案。
但是:例如,对于GCC 4.8,MinGW,编译器会触发警告消息,并且程序按照我描述的行为进行编译。因此,它被认为是有效的常量,如 '\x100020' 并且其值为 0x20。
C 标准在第 6.4.4.4 节中定义了语法和语义。我将引用 C1570 标准的 N11 草案。
第6段:
反斜杠和字母 x 后面的十六进制数字 十六进制转义序列被视为构造的一部分 整数字符常量的单个字符或单个字符 宽字符为宽字符常量。的数值 如此形成的十六进制整数指定所需值 字符或宽字符。
第9段:
约束
八进制或十六进制转义序列的值应位于 相应类型的可表示值范围:
后跟一个表,说明没有前缀,"对应类型"是unsigned char
。
因此,假设0xFFFFAA
超出了类型 unsigned char
的可表示范围,字符常量'xFFFFAA'
是约束冲突,需要编译时诊断。编译器可以自由地完全拒绝您的源文件。
如果你的编译器至少没有警告你这一点,它就不符合 C 标准。
是的,该标准确实说无符号类型具有模块化(环绕)语义,但这仅适用于算术表达式和某些转换,而不适用于常量的含义。
(如果您的系统上CHAR_BIT >= 24
,它是完全有效的,但这很少见;通常CHAR_BIT == 8
。
如果编译器选择仅发出警告,然后继续编译源代码,则行为是未定义的(仅仅是因为标准未定义行为)。
另一方面,如果你实际上的意思是'xFFFFAA'
,那不会被解释为十六进制。(我看到这只是一个错字,并且该问题已被编辑以更正它,但无论如何我都会把它留在这里。其价值由执行定义,如第10段所述:
包含多个整数字符常量的值 字符(例如, 'ab'),...,是实现定义的。
包含多个字符的字符常量是一种几乎无用的语言功能,意外使用的频率高于有意使用的频率。
是的,xFFFFAA
的值应该可以用 unsigned char
表示。
6.4.4.4 9 约束
八进制或十六进制转义序列的值应位于 无符号字符类型的可表示值范围 整数字符常量。
但C99也说,
6.4.4.4 10 语义
包含多个整数字符常量的值 字符(例如,"ab"),或包含字符或转义序列 不映射到单字节执行字符,是 实现定义。
因此,结果值应在无符号 char([0, 255],如果 CHAR_BIT == 8) 范围内。但至于哪一个,就要看编译器、架构等了。