int main()
{
0xD-0; // Fine
0xE-0; // Fails
}
第二行在clang和gcc上都无法编译。任何其他十六进制常量结尾都可以(0-9,A-D, F)。
错误:
<source>:4:5: error: unable to find numeric literal operator 'operator""-0'
4 | 0xE-0;
| ^~~~~
我有一个修复(在常量之后和减法之前添加一个空格),所以我主要想知道为什么?这和它认为这里有一个指数有关吗?
https://godbolt.org/z/MhGT33PYP
实际上,这种行为是c++标准强制要求的(并且有文档记录),尽管看起来很奇怪。这是因为c++是如何使用预处理令牌(又名pp-tokens)进行编译的。
如果我们仔细观察编译器如何为数字生成token:
预处理数字由一个数字组成,前面可以有一个句号,后面可以有字母、下划线、数字、句点和e+ e- e+ e-中的任意一种。
根据此,编译器读取0x
,然后E-
,它将其解释为数字的一部分,因为在数字pp-令牌中允许有E-
,并且在E
和-
之间没有空格(这就是为什么添加空格是一个简单的修复)。
这意味着0xE-0
被接收为单个预处理标记。换句话说,编译器将其解释为一个数字,而不是两个数字0xE
和0
以及一个操作-
。因此,编译器期望E
表示浮点数字面量的指数。
现在让我们看一下c++是如何解释浮点量的。请看"例子"下面的部分。它给这个奇怪的代码示例:
<< "n0x1p5 " << 0x1p5 // double
<< "n0x1e5 " << 0x1e5 // integer literal, not floating-point
E
被解释为整数字面值的一部分,并且不是使数字为十六进制浮点文字!因此,编译器将0xE
识别为单个十六进制整数。然后是-0
,它在技术上属于同一预处理令牌的一部分,因此不是操作符和另一个整数。哦哦。现在无效,因为没有-0
后缀。
因此编译器报告一个错误,如下所示