编写十六进制和十进制数的简单加法的约定

Conventions to write simple additions of hexadecimal and decimal numbers

即使是老朋友,恐怕我(不再)完全掌握 C 中常量的解析。以下 1-liner 中的第二个无法编译:

int main( void ) { return (0xe +2); }
int main( void ) { return (0xe+2); }

$ gcc -s weird.c

weird.c: In function ‘main’:
weird.c:1:28: error: invalid suffix "+2" on integer constant
int main( void ) { return (0xe+2); }
                           ^

编译失败的原因可能是0xe+2按照C11标准条款6.4.4.2被解析为十六进制浮点常量。我的问题是是否存在 约定 来在 C 中编写简单的十六进制和十进制数的加法,我不喜欢在解析时必须依赖白色 space。

这是 gcc 版本 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)。预处理后停止编译(-E)显示编译失败发生在 gcc 而不是 cpp。

因为GCC认为0xe+2是一个浮点数,而这只是两个整数相加。

根据cppreference

Due to maximal munch, hexadecimal integer constants ending in e and E, when followed by the operators + or -, must be separated from the operator with whitespace or parentheses in the source:

int x = 0xE+2;   // error
int y = 0xa+2;   // OK
int z = 0xE +2;  // OK
int q = (0xE)+2; // OK

My question is whether a convention exists to write simple additions of hexadecimal and decimal numbers in C

惯例是使用spaces。这实际上是由 C11 6.4 §3 强制执行的:

Preprocessing tokens can be separated by white space; this consists of comments (described later), or white-space characters (space, horizontal tab, new-line, vertical tab, and form-feed), or both.

其中普通的space是常用的

语言中到处存在类似的奇异问题,一些例子:

  • ---a 必须重写为 - --a.
  • a+++++b 必须重写为 a++ + ++b.
  • a /// comment
    b;
    必须重写为
    a / // comment
    b

等等。所有这些情况的罪魁祸首是遵循 so-called "maximal munch rule"、C11 6.4 §4:

的令牌解析器

If the input stream has been parsed into preprocessing tokens up to a given character, the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token.

在这种特定情况下,pre-processor 在构建一个名为 [=64= 的 pre-processing 标记时,不区分浮点常量和整数常量],在C11 6.4.8中定义:

pp-number e sign
pp-number E sign
pp-number p sign
pp-number P sign
pp-number .

A preprocessing number begins with a digit optionally preceded by a period (.) and may be followed by valid identifier characters and the character sequences e+, e-, E+, E-, p+, p-, P+, or P-.

这里,就 pre-processor 而言,pp-number 显然不必是浮点常量。


( 作为旁注,在字符串中终止十六进制转义序列时也存在类似的约定。例如,如果我想在新行上打印字符串 "ABBA",那么我不能写

puts("\xD\xABBA"); (CR+LF+字符串)

因为本例中的字符串可以解释为十六进制转义序列的一部分。相反,我必须使用白色 space 来结束转义序列,然后依赖 pre-processor 字符串连接:puts("\xD\xA" "BBA")。目的是一样的,指导pre-processor如何解析代码。 )