You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

超大数值字面量的类型选择规则与编译器合规性问询

C++十进制字面量类型判定的编译器行为与标准疑问

我测试了GCC、clang、MSVC三大编译器的行为,对哪种符合C++标准存在疑问,以下是测试代码:

// p43.cxx
#include <type_traits>

constinit auto n1 = 9223372036854775807; // 2^63 - 1
static_assert(std::is_same_v<decltype(n1), signed long long int>);

constinit auto n2 = 9223372036854775808; // 2^63
constinit auto n3 = 18446744073709551615; // 2^64 - 1

#if defined _MSC_VER || defined __clang__
static_assert(std::is_same_v<decltype(n2), unsigned long long int>);
static_assert(std::is_same_v<decltype(n3), unsigned long long int>);
#elif defined __GNUC__
static_assert(std::is_same_v<decltype(n2), __int128>);
static_assert(std::is_same_v<decltype(n3), __int128>);
#endif

#if defined __GNUC__ && !defined __clang__
constinit auto n4 = 18446744073709551616; // 2^64
static_assert(std::is_same_v<decltype(n4), int>);
#endif

执行以下语法检查命令均无错误:

g++ -std=c++2c p43.cxx -Wall -Wextra -Wpedantic -fsyntax-only
clang++ -std=c++2c p43.cxx -Wall -Wextra -Wpedantic -fsyntax-only
cl /nologo /std:c++latest /nologo /Wall /wd4577 p43.cxx /Zs

(cl编译时禁用C4577以简化输出)

根据C++标准草案:

[lex.icon]/3 十进制字面量应优先选择int、long int或long long int类型;
[lex.icon]/4 若上述类型无法容纳字面量,允许使用扩展整数类型(如__int128)。

测试结果

  • 所有编译器均判定n1的类型为signed long long int,符合预期。
  • 对于n2n3
    • MSVC无警告,将二者类型判定为unsigned long long int
    • clang提示“integer literal is too large to be represented in a signed integer type, interpreting as unsigned”,同样判定为unsigned long long int
    • GCC给出类似警告,但选择了有符号扩展类型__int128
  • 仅GCC支持定义n4,但将其类型判定为int;MSVC和clang会直接报错提示数值过大。

疑问解答

  1. 若不支持signed __int128,9223372036854775808和18446744073709551615是否应判定为语法错误?
    根据C++标准,十进制字面量属于有符号类型范畴,当标准有符号整数类型(int/long/long long)无法容纳时,必须优先使用支持的扩展有符号整数类型;若不存在能容纳该值的扩展有符号类型,这个字面量属于无效的无类型字面量,应判定为语法错误。clang和MSVC将其转为无符号字面量的行为属于编译器扩展,不符合标准的严格规定,但属于常见的兼容处理逻辑。

  2. GCC默认支持__int128,但为何将18446744073709551616解析为int类型,而非能容纳它的signed __int128?
    这是GCC的非标准行为。按照标准,该数值可以被signed __int128容纳,理应选择此类型,但GCC在处理超过unsigned long long范围的十进制字面量时,会触发整数溢出回绕逻辑,将其截断为int类型,这属于编译器历史遗留的非标准处理方式,不符合C++标准的要求。

(补充:测试平台为PC Windows x86-64 LLP64)

内容的提问来源于stack exchange,提问作者Sventikas

火山引擎 最新活动