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
相关产品推荐
相关产品推荐

