在可变参数函数中,
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
时,我注意到有趣的行为:
#include <stdarg.h>
#include <stdio.h>
void example_function(int arg_count, ...) {
va_list args;
va_start(args, arg_count);
int i = 0;
while (i < arg_count) {
printf("%d\n", va_arg(args, int));
i++;
}
va_end(args);
}
int main() {
example_function(3, 1, 2, 3);
return 0;
}
在此代码中:
gp_offset
从 8 开始,并在 while 循环中每次调用 va_arg 时递增 8。fp_offset
保持固定为 48。overflow_arg_area
和 reg_save_area
使用垃圾值进行初始化。我想了解:
gp_offset
时 va_arg
都会增加 8?fp_offset
固定为48?overflow_arg_area
和reg_save_area
指向垃圾值?gp_offset
增加 8,因为参数保存在通用寄存器中。
在调用带参数的函数之前,前 6 个参数将首先移至寄存器,其余参数移至堆栈(这取决于您的机器、操作系统...),然后调用该函数。每个寄存器有 8 个字节。fp_offset
是一个浮点偏移量,当 va_arg 返回的当前参数是 double 或 float 类型时,它会被更新。double 和 float 有专门的寄存器,如果我记得的话,它们每个的大小都是 16 个字节。