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

Ubuntu20.04 64位GCC9.4.0下va_list大小异常及代码报错求助

va_list类型与操作疑问解析

问题背景

在Ubuntu 20.04 64位系统、GCC 9.4.0环境下,我原本认为stdarg.h中va_list是typedef char* va_list,大小应为8字节,但实际通过sizeof(va_list)得到的结果是24字节,对此存在疑问。

同时我运行了两段代码,第一段尝试手动操作va_list指针却报错,第二段使用标准va_arg则正常运行,想知道报错的原因。

第一段报错代码

#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
void print_num( int count, ...){
        va_list args;
        printf("sizeof(args):%d\n",sizeof(va_list));
        va_start(args,count);
        for( int i = 0; i < count; i++ ){
//            printf("*args = %d\n",va_arg(args,int));
              printf("*args = %d\n",*(int*)args);
              args += 4;
        }
        va_end(args);
}
int main(){
        print_num(5,1,2,3,4,5);
        return 0;
}

报错信息:

change_function.c:13:8: error: assignment to expression with array type 13 |   args += 4;

第二段正常运行代码

#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
void print_num( int count, ...){
        va_list args;
        printf("sizeof(args):%d\n",sizeof(va_list));
        va_start(args,count);
        for( int i = 0; i < count; i++ ){
                printf("*args = %d\n",va_arg(args,int));
//              printf("*args = %d\n",*(int*)args);
//      args += 4;
        }
        va_end(args);
}
int main(){
        print_num(5,1,2,3,4,5);
        return 0;
}

问题解答

1. va_list的真实类型与大小

你对va_list的理解停留在旧的实现上,在GCC的x86_64(64位)平台下,va_list并不是简单的char*,而是一个数组封装的结构体,用来存储处理可变参数所需的上下文信息(比如寄存器状态、栈指针等),所以它的大小是24字节,而非你预期的8字节。

GCC在x86_64平台的stdarg.h中,va_list的定义大致如下:

typedef struct {
    unsigned int gp_offset;
    unsigned int fp_offset;
    void *overflow_arg_area;
    void *reg_save_area;
} va_list[1];

用数组类型封装结构体,是为了让va_list具备值传递时的特殊行为,同时也直接导致你无法对其进行指针算术操作。

2. 第一段代码报错的原因

报错信息assignment to expression with array type明确说明:args是数组类型变量,而数组变量不能作为左值进行赋值或复合赋值操作(比如+=)。你试图把va_list当作普通指针来操作,完全违反了它的类型定义规则。

另外,即便va_list是指针类型,手动args +=4的操作也是错误的:

  • x86_64平台会用寄存器传递部分参数,手动移动指针无法正确获取这部分参数;
  • va_arg会自动处理参数的对齐和类型宽度,手动操作会破坏va_list的上下文,触发未定义行为。

正确做法

必须使用标准的可变参数宏来处理可变参数:

  • va_start:初始化va_list,绑定到可变参数的前一个固定参数;
  • va_arg:按指定类型获取下一个参数,自动推进va_list的位置;
  • va_end:清理va_list的上下文。

这些宏是为不同平台的参数传递规则量身定制的,能保证代码的可移植性和正确性,绝对不要试图手动操作va_list的内部结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 20:50:25