为何十进制字面量可超出long long最大值?C++编译行为解析
关于十进制整数字面量与C++标准的疑问解答
1. 为什么十进制字面量超出long long最大值却没直接报错?
你提到《C++ Primer》里说十进制字面量会适配能容纳它的最小类型(int、long、long long),超出则报错,这其实是C++11及以后的标准规则,但在C98(或GNU扩展的C98模式,也就是你未指定标准时的默认模式)下,规则有明显差异:
- 在C++98标准中,十进制整数字面量的可选类型是
int、long、unsigned long——注意此时long long还不是标准类型,只是GCC等编译器的扩展特性。当字面量超出long的最大值时,编译器会自动将其视为unsigned long;如果超出unsigned long的范围,就会触发未定义行为(GCC在这里的处理是按模2^N回绕,比如你测试的18446744073709551616超出unsigned long long最大值,就回绕到了0)。 - 当你开启C++11标准后,规则严格遵循:十进制字面量会优先尝试
signed类型(int→long→long long),如果这些类型都容纳不下,才会尝试unsigned long long;如果连unsigned long long都装不下,编译器会将其视为扩展的128位有符号整数(比如GCC的__int128),这时候std::ostream没有对应的输出重载,就会出现你看到的ambiguous overload错误。
你一开始没注意到编译警告,是因为CodeBlocks默认重建项目时不会重复输出之前的警告信息,而这些警告其实已经明确提示了问题:integer constant is so large that it is unsigned说明编译器已经把超出signed long long的字面量转为unsigned类型了。
2. 为什么未指定标准时编译器支持<limits>头文件?
<limits>是C++98就已经存在的标准头文件,它提供了模板化的数值限界查询(比如std::numeric_limits)。你在未指定标准时能使用LONG_LONG_MAX和ULONG_LONG_MAX,是因为GCC在默认的GNU++98模式下启用了扩展——这些宏原本是C99标准引入的,GCC把它们加到了<limits>头文件中作为扩展支持。
而当你开启严格C++11模式后:
- C++11标准正式引入了
long long类型,对应的标准宏是<climits>里的LLONG_MAX和ULLONG_MAX,<limits>头文件更推荐使用std::numeric_limits<long long>::max()这种模板方式获取值,所以不再提供非标准的LONG_LONG_MAX宏。 - 同时,严格C++11模式下会禁用一些GNU扩展,所以你只能通过
<climits>获取标准的LLONG_MAX和ULLONG_MAX。
补充测试建议
如果你想验证不同标准下的行为,可以在编译时显式指定标准:
- 编译C++98:
g++ -std=c++98 main.cpp - 编译C++11:
g++ -std=c++11 main.cpp - 编译C++17:
g++ -std=c++17 main.cpp
这样能更清晰地看到不同标准对整数字面量类型推导的影响。
内容的提问来源于stack exchange,提问作者Sviatozar Petrenko
相关产品推荐
相关产品推荐

