位域字段的类型与大小:MSVC正常编译Clang报警告谁正确?
位域的整数提升与编译器行为差异
以下代码在MSVC中可正常编译运行,但在Clang中会触发格式警告:
#include <stdint.h> #include <stdio.h> struct Bob { unsigned long long foo : 10; unsigned long long bar : 10; }; int main() { Bob b{}; auto a = b.foo; static_assert(sizeof(a) == sizeof(uint64_t), "wat"); printf("%llx", a); printf("%llx", b.foo); }
Clang给出的警告信息:
<source>:15:17: warning: format specifies type 'unsigned long long' but the argument has type 'int' [-Wformat] printf("%llx", b.foo); ~~~~ ^~~~~ %x
标准规则分析
根据C++标准的整数提升规则:当无符号整数类型的位域,其取值范围能被int完全容纳时,该位域在被转换为右值(比如作为函数参数传递)时,会被提升为int类型;只有当位域的取值范围超出int的表示范围时,才会提升为对应的无符号底层类型。
这里的位域foo是unsigned long long类型但仅占10位,其最大值为2^10 - 1 = 1023,远小于普通int类型的最小表示范围(至少能容纳-32768到32767),因此按照标准,b.foo作为函数参数传递给printf时,应该被提升为int类型。
编译器行为对比
- Clang:严格遵循标准规则,识别出
b.foo被提升为int,而printf的%llx格式符要求参数是unsigned long long,因此触发格式不匹配的警告,行为符合标准。 - MSVC:未按照标准进行整数提升,直接将位域当作底层的
unsigned long long类型处理,因此既不会触发警告,static_assert也能通过,但这不符合C++标准的规定。
内容的提问来源于stack exchange,提问作者Mike Vine
相关产品推荐
相关产品推荐

