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

Baa*_*ard 23 c parsing gcc c99

即使是一个老朋友,我担心我不再(完全)完全掌握在C中解析常量.下面的第二个1行无法编译:

int main( void ) { return (0xe +2); }
int main( void ) { return (0xe+2); }
Run Code Online (Sandbox Code Playgroud)

$ 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); }
                           ^
Run Code Online (Sandbox Code Playgroud)

根据C11标准条款6.4.4.2,编译失败的原因可能是0xe + 2被解析为十六进制浮点常量.我的问题是,是否存在在C中编写十六进制和十进制数的简单加法的约定,我不喜欢在解析时依赖于空格.

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

msc*_*msc 20

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

根据cppreference:

由于最大的munch,十六进制整数常量e以及E在操作符+或后面跟随操作符时-,必须与源中的空格或括号分隔操作符:

int x = 0xE+2;   // error
int y = 0xa+2;   // OK
int z = 0xE +2;  // OK
int q = (0xE)+2; // OK
Run Code Online (Sandbox Code Playgroud)

  • @baard:whitespace*是*惯例. (6认同)

Lun*_*din 13

我的问题是,是否存在在C中编写十六进制和十进制数的简单加法的约定

惯例是使用空格.这实际上是C116.4§3规定的:

预处理令牌可以用空格分隔; 这包括注释(稍后描述)或空白字符(空格,水平制表符,换行符,垂直制表符和换页符)或两者.

普通空间是常用空间.

在语言中存在类似的异国情调问题,例如:

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

等等.所有这些情况的罪魁祸首都是令牌解析器,它遵循所谓的"最大咀嚼规则",C116.4§4:

如果输入流已被解析为预处理令牌直到给定字符,则下一个预处理令牌是可构成预处理令牌的最长字符序列.

在这种特定情况下,当预处理器构建一个名为pp-number的预处理令牌时,预处理器不会对浮点常量和整数常量进行任何区分,这在C11 6.4.8中定义:

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

预处理数字以可选地在句点(.)之后的数字开始,并且可以跟随有效的标识符字符和字符序列e +,e-,E +,E-,p +,p-,P +或P-.

在这里,就预处理器而言,pp-number显然不必是浮点常数.


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

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

因为在这种情况下字符串可以解释为十六进制转义序列的一部分.相反,我必须使用空格来结束转义序列,然后依靠预处理器字符串连接:puts("\xD\xA" "BBA").目的是一样的,指导预处理器如何解析代码.)