C++中以E结尾的十六进制常量做减法编译报错原因咨询
问题复现
以下代码在GCC、Clang编译器下均会出现编译失败的情况:
int main() { 0xD-0; // 编译正常 0xE-0; // 编译失败 }
经测试,十六进制常量以0-9、A-D、F结尾时,直接后接减号和数字都能正常编译,只有以E/e结尾时会触发报错,报错信息如下:
<source>:4:5: error: unable to find numeric literal operator 'operator""-0' 4 | 0xE-0; | ^~~~~
根本原因
这个现象不是编译器bug,是C++标准规定的词法分析规则导致的,你的猜测方向正确:常量末尾的E确实触发了指数部分的匹配逻辑,核心原因是预处理数字(pp-number)的最长匹配(贪吃蛇)规则。
C++预处理阶段扫描token时,对数字序列会遵循最长匹配原则:尽可能多地把连续字符纳入同一个token,只要字符序列符合pp-number的语法规则就不会提前截断。pp-number的语法中明确包含以下产生式:
pp-number e signpp-number E signpp-number p signpp-number P sign
其中sign指代+或-。也就是说:只要当前扫描的数字序列后接e/E/p/P,紧接着又跟了正负号,这整段连续字符都会被划入同一个预处理数字token,不会把正负号识别为独立的运算符。
对应代码里的两种写法:
- 写
0xD-0时,字符D不在上述触发规则的字符范围内,扫描到D后遇到-,不符合pp-number继续匹配的条件,因此token被拆分为0xD(十六进制常量)、-(减号运算符)、0(整数常量),构成合法的减法表达式,编译通过。所有以0-9、A-C、F结尾的十六进制常量后直接接减号,都不会触发该规则,因此编译正常。 - 写
0xE-0时,扫描到E后紧接着遇到-,完全匹配pp-number E sign的规则,因此整个0xE-0会被识别为同一个预处理数字token。后续编译器尝试将这个token解析为内置整数/浮点数字面量时,发现它不符合任何内置数字的语法,就会转而查找对应的用户自定义字面量运算符operator""-0,该运算符不存在,因此抛出编译错误。
修复方案
在十六进制常量和减号之间添加空格即可:空格会终止pp-number的匹配流程,让-被识别为独立的减号运算符,表达式0xE - 0就可以正常编译。
内容的提问来源于stack exchange,提问作者Mike Vine
相关产品推荐
相关产品推荐

