3

假设我们在 C 中编写了以下字符常量:

  '\xFFFFAA'  

它的数值是多少?

标准C99说:

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

除了:

  • 的值范围signed char包含在 的值范围内int
  • 和的大小(以位为单位)char相同:1 个字节。 unsigned charsigned char
  • 字节的大小由 给出CHAR_BIT,其值至少为 8。

假设我们有典型的情况CHAR_BIT == 8
另外,让我们假设这charsigned char给我们的。

遵循规则:常量 '\xFFFFAA' 有 type int,但它的值可以用 a 表示unsigned char尽管它的实际值适合 a char
根据这些规则,'\xFF' 的示例将为我们提供:

  (int)(char)(unsigned char)'\xFF' == -1

第一次转换unsigned char来自“可以表示为无符号字符”要求。
第二个演员char来自“值适合一个字符”的要求。
第三次转换int 来自“具有 int 类型”要求。

但是,常数'\xFFFFAA'太大,不能“表示”为unsigned int
它的价值是多少?

我认为该值是(char)(0xFFFFAA % 256)由于标准或多或少地说明了以下内容的结果:

  • 对于无符号整数类型,如果一个值大于该类型可以表示的最大M,则该值是取余数模M后得到的。

我对这个结论是否正确?

编辑我已经被@KeithThompson说服:他说,根据标准,一个大的十六进制字符常量是违反约束的。
所以,我会接受这个答案。

但是:例如,对于 GCC 4.8、MinGW,编译器会触发警告消息,并且程序会按照我描述的行为进行编译。因此,像'\x100020'这样的常量被认为是有效的,其值为0x20。

4

2 回答 2

4

C 标准在 6.4.4.4 节中定义了语法和语义。我将引用 C11 标准的N1570草案。

第 6 段:

反斜杠后面的十六进制数字和十六进制转义序列中的字母x被视为整数字符常量的单个字符或宽字符常量的单个宽字符的构造的一部分。如此形成的十六进制整数的数值指定所需字符或宽字符的值。

第 9 段:

约束

八进制或十六进制转义序列的值应在相应类型的可表示值范围内:

后跟一张表,说没有前缀,“对应的类型”是unsigned char.

因此,假设它0xFFFFAA超出了 type 的可表示范围unsigned char,则字符常量'\xFFFFAA'是违反约束的,需要编译时诊断。编译器可以完全拒绝您的源文件。

如果您的编译器至少没有对此发出警告,则说明它不符合 C 标准。

是的,标准确实说无符号类型具有模块化(环绕)语义,但这仅适用于算术表达式和某些转换,不适用于常量的含义。

(如果CHAR_BIT >= 24在您的系统上,它是完全有效的,但这很少见;通常CHAR_BIT == 8。)

如果编译器选择仅发出警告,然后继续编译您的源代码,则行为未定义(仅仅是因为标准没有定义行为)。

另一方面,如果您实际上是指'xFFFFAA',则不会将其解释为十六进制。(我认为这只是一个错字,并且已对问题进行了编辑以更正它,但无论如何我将把它留在这里。)它的值是实现定义的,如第 10 段所述:

包含多个字符(例如 'ab')的整数字符常量的值,...,是实现定义的。

包含多个字符的字符常量几乎是一种无用的语言特性,其使用频率高于有意使用的频率。

于 2013-09-08T00:59:58.113 回答
1

是的, 的值\xFFFFAA应该可以表示为unsigned char

6.4.4.4 9 约束

八进制或十六进制转义序列的值应在整数字符常量的 unsigned char 类型的可表示值范围内。

但 C99 也说,

6.4.4.4 10 语义

包含多个字符(例如,'ab')或包含不映射到单字节执行字符的字符或转义序列的整数字符常量的值是实现定义的。

所以结果值应该在 unsigned char([0, 255], if CHAR_BIT == 8) 的范围内。但至于哪一个,则取决于编译器、架构等。

于 2013-09-08T01:01:06.690 回答