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

时间:2018-04-11 06:19:15

标签: c parsing gcc c99

即使是一个老朋友,我担心我不再(完全)完全掌握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。

2 个答案:

答案 0 :(得分:20)

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

根据cppreference

  

由于最大的munch,eE结尾的十六进制整数常量,   当跟随运算符+-时,必须与运算符分开   源中包含空格或括号的运算符

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")。目的是一样的,指导预处理器如何解析代码。 )