You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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字节

标准合规性分析

  1. 0宽度位域的实现定义行为
    C++标准规定,0宽度位域的作用是强制后续位域对齐到其类型的存储单元边界,但当结构体仅包含一个0宽度位域时,标准未明确规定该结构体的大小与对齐规则——这属于实现定义行为,不同编译器可自行处理此类场景。

  2. __attribute__((aligned))的非标准扩展
    __attribute__((aligned))是GCC/clang专属的编译器扩展,不属于C标准范畴。它对Talllong类型的对齐要求,与0宽度位域组合后,g和clang++的处理逻辑不一致,直接导致struct S94的大小出现差异。

  3. 可变参数函数的未定义行为
    可变参数函数中,va_arg要求实际传入的参数类型与指定类型严格匹配(包括大小和对齐)。由于struct S94的大小在不同环境下不一致,va_arg读取arg1后栈指针偏移错误,进而导致读取tmp时拿到错误值——这属于未定义行为,C++标准不保证此类代码的执行结果,编译器无需对此负责。

结论

这段代码既涉及实现定义行为(结构体大小与对齐),又触发了未定义行为(可变参数的栈读取错误),因此标准不会保证其执行结果,不同编译器、架构下的表现差异完全符合预期。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 06:35:24