C 中 "big" 个字符的十六进制常量的值是多少?



>假设我们用C写下以下字符常量:

  'xFFFFAA'  

它的数值是多少?

标准C99说:

  • 字符常量的类型为 int
  • 十六进制字符常量可以表示为unsigned char
  • 基本字符常量的值为非负值。
  • 任何字符常量的值都适合 char 的范围。

此外:

  • signed char 的值范围包含在 int 的值范围内。
  • charunsigned charsigned 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) 范围内。但至于哪一个,就要看编译器、架构等了。

最新更新