C++中带对齐属性的含零宽位域空结构体是否为未定义行为?
非常规C++代码的行为分析与标准合规性
测试代码
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdarg.h> extern void *memset (void *__s, int __c, size_t __n); typedef long long int Talllong __attribute__((aligned)); struct S94 { Talllong: 0; }; struct S94 s94; void check94va(int z, ...) { va_list ap; va_start(ap, z); struct S94 arg1 = va_arg(ap, struct S94); long long int tmp = va_arg(ap, long long); //printf("result = %lld\n", tmp); if (tmp != 2LL) { printf("Fails!!!!\n"); } va_end(ap); } int main(void) { memset(&s94, '\0', sizeof(s94)); //printf("sizeof(s94) = %ld\n", sizeof(s94)); check94va(1, s94, 2LL); return 0; }
代码表现差异
- g下可正常运行,clang下执行失败
- 架构差异:
- aarch64:
long long占8字节,struct S94占16字节 - x86-64:
struct S94仅占1字节
- aarch64:
标准合规性分析
0宽度位域的实现定义行为
C++标准规定,0宽度位域的作用是强制后续位域对齐到其类型的存储单元边界,但当结构体仅包含一个0宽度位域时,标准未明确规定该结构体的大小与对齐规则——这属于实现定义行为,不同编译器可自行处理此类场景。__attribute__((aligned))的非标准扩展__attribute__((aligned))是GCC/clang专属的编译器扩展,不属于C标准范畴。它对Talllong类型的对齐要求,与0宽度位域组合后,g和clang++的处理逻辑不一致,直接导致struct S94的大小出现差异。可变参数函数的未定义行为
可变参数函数中,va_arg要求实际传入的参数类型与指定类型严格匹配(包括大小和对齐)。由于struct S94的大小在不同环境下不一致,va_arg读取arg1后栈指针偏移错误,进而导致读取tmp时拿到错误值——这属于未定义行为,C++标准不保证此类代码的执行结果,编译器无需对此负责。
结论
这段代码既涉及实现定义行为(结构体大小与对齐),又触发了未定义行为(可变参数的栈读取错误),因此标准不会保证其执行结果,不同编译器、架构下的表现差异完全符合预期。
内容的提问来源于stack exchange,提问作者hstk
相关产品推荐
相关产品推荐

