即使是一个老朋友,我担心我不再(完全)完全掌握C语言中常量的解析。以下第一个1-liners无法编译:
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); }
^
编译失败的原因可能是根据C11标准条款6.4.4.2将0xe + 2解析为十六进制浮点常量。我的问题是,是否存在约定来在C中编写十六进制和十进制数的简单加法,我不喜欢在解析时依赖于空格。
这是使用gcc版本5.4.0 20160609(Ubuntu 5.4.0-6ubuntu1~16.04.9)。在预处理(-E)之后停止编译显示编译失败发生在gcc而不是cpp。
答案 0 :(得分: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
答案 1 :(得分: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中定义0.8:
pp-number e 签收
pp-number E 标志
pp-number p 签收
pp-number P 符号
pp-number 。预处理编号以数字开头,可选地以句点(。)开头,并且可以 后跟有效的标识符字符和字符序列e +,e-,E +,E-, p +,p-,P +或P - 。
这里,就预处理器而言, pp-number 显然不一定是浮点常数。
(作为旁注,在终止字符串内部的十六进制转义序列时也存在类似的约定。例如,如果我想在新行上打印字符串"ABBA"
,那么我就不能写
puts("\xD\xABBA");
(CR + LF + string)
因为在这种情况下字符串可以解释为十六进制转义序列的一部分。相反,我必须使用空格来结束转义序列,然后依赖预处理器字符串连接:puts("\xD\xA" "BBA")
。目的是一样的,指导预处理器如何解析代码。 )