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

Mac M1平台gcc-11调用va_arg读取可变参数值异常问题

va_arg读取M1设备gcc-11编译程序可变参数异常问题

问题现象

在搭载M1芯片的Mac设备上使用va_arg读取函数可变参数时出现异常:使用Apple clang运行代码输出结果符合预期,同设备使用Homebrew安装的gcc-11运行相同代码时,会读取到无效乱码值。

测试代码如下:

#include <stdio.h>
#include <stdarg.h>

#define ND_indices size_t

void llF(ND_indices rank, ...){
    /* Get all the args of type ND_indices*/
    ND_indices arg_val;
    va_list ap;
    va_start(ap, rank);
    for (ND_indices i=1; i<=rank; ++i){
        arg_val = va_arg(ap, ND_indices); 
        printf("%lu \n",arg_val);
    }
    va_end(ap);
}

int main()
{   llF(10,3,2,4,2,3,4,4,6,7,6);
    //printf("Hello World");

    return 0;
}

运行结果对比

  • 使用Apple clang version 13.1.6 (clang-1316.0.21.2.5)编译运行,输出符合预期:
3 
2 
4 
2 
3 
4 
4 
6 
7 
6 
  • 使用Homebrew安装的gcc-11在M1版Mac上编译运行,输出乱码值:
3 
2 
4 
4294967298 
4294967299 
4294967300 
4294967300 
9331036219741569030 
4294967303 
4294967302 

复现条件说明

  • 编译选项:gcc-11 test.c -Wall
  • 特殊规律:即使用gcc-11编译,当传入3个可变参数时代码可正常运行
  • 交叉验证结果:在x86架构设备上分别使用clang、gcc-10、icc编译运行该代码,以及多个在线C编译器测试,均未复现该问题。

问题根因

该问题本质是未定义行为触发的编译器实现差异:

  1. 代码中传入可变参数的字面量3,2,4...默认是int类型(32位宽度),但va_arg读取时指定的类型是size_t(ARM64平台下为64位无符号整型)。C标准明确要求va_arg读取的类型必须和实际传入参数的类型(经过默认参数提升后)严格匹配,否则行为未定义。注意默认参数提升仅会将宽度小于int的类型转换为int、float转换为double,int类型本身不会自动扩展到64位。
  2. 不同平台/编译器的ABI实现差异导致表现不同:
    • x86_64平台的System V ABI要求所有整数参数传递时都扩展到64位宽度,高32位自动清零,因此误读64位时不会出现乱码
    • Apple clang遵循Darwin ARM64 ABI规范,对传入可变参数列表的int类型值会自动零扩展到64位,因此读取64位值结果正常
    • M1平台上Homebrew安装的gcc-11对可变参数的实现没有做上述自动扩展,int类型参数仅占32位宽度,剩余高32位为寄存器/栈上的残留垃圾值,按64位读取时就会把垃圾值一并读出,出现乱码
  3. 传入3个可变参数时运行正常属于巧合:ARM64架构下函数参数优先通过X0-X7寄存器传递,前几个参数所在寄存器的高32位刚好为0,没有触发垃圾值读取。

修复方案

传入可变参数时,显式将参数转换为和va_arg读取一致的size_t类型,避免类型不匹配:

// 方式1:强转类型
llF(10, (size_t)3, (size_t)2, (size_t)4, (size_t)2, (size_t)3, (size_t)4, (size_t)4, (size_t)6, (size_t)7, (size_t)6);
// 方式2:直接使用匹配宽度的字面量后缀
// llF(10, 3UL, 2UL, 4UL, 2UL, 3UL, 4UL, 4UL, 6UL, 7UL, 6UL);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 20:15:52