我正在尝试弄清楚va_start()和va_arg()宏背后是什么。下面的代码运行良好。
#include <iostream>
#include <cstdarg>
void f(double a, double b, ...)
{
va_list arg;
va_start(arg, b);
double d;
while((d = va_arg(arg, double)) != 0)
{
std::cout << d << '\n';
}
}
int main(int argc, char *argv[])
{
f(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 0.0);
return 0;
}
尽管如此,我还是写道:
typedef char* va_list;
#define _INTSIZEOF(n) \
((sizeof(n)+sizeof(int)-1) &~(sizeof(int)-1))
#define va_start(ap,v) \
(ap = (va_list)&v + _INTSIZEOF(v))
#define va_arg(ap,t) \
(*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
#define va_end(ap) (ap = (va_list)0)
输出变得更复杂了,例如1 -0.0409377 -0.0409377 4.88084e-270 4.85706e-270 1 2 3 4 5 6 7 8 9。我认为可变参数放在最后声明的参数的旁边,但显然有更复杂的情况。如果有人揭发我哪里错了或者到底发生了什么,我会非常高兴的。
发布于 2013-03-29 23:09:16
va_start
、va_arg
和别忘了va_end
是特定于编译器的。你不能仅仅把它们从别的地方拿来,然后期望它们能工作。如果你是一名编译器工程师,最好按照手册中的说明来使用它们,并且只试着理解它们的内部工作原理。
您可以在编译器的源代码中找到它;)
发布于 2013-03-29 23:50:18
您的手写宏将在一台机器上工作,该机器总是传递堆栈上的所有参数,并将较小的类型填充到sizeof(int)。然而,许多机器(现在大多数?)不要在堆栈上传递参数--而是在寄存器中传递参数,并且只有在寄存器中无法容纳太多参数时才使用堆栈。
因此,为了处理va_args,编译器需要知道ABI,以及在什么情况下将把哪些参数放在哪里。通常要做的是让va_list包含多个数组(足以容纳所有可能包含args的寄存器)和多个指针(通常,每种类型的寄存器一个指针,堆栈一个指针。va_start将所有参数寄存器转储到数组中并初始化指针,然后va_arg计算出给定参数类型将被传递到哪种类型的寄存器中,并将值从适当的点中取出。因此,对于一个假设的处理器,其中8个regs用于整数/指针参数,8个regs用于浮点/双精度参数,您可能具有如下内容:
typedef struct {
intptr_t iregs[8], *iptr;
double fregs[8], *fptr;
char *spptr;
} va_list;
inline void _builtin_va_start(va_list &ap, arg) {
// dump the registers might be used to pass args into ap->iregs and ap-fregs,
// setup iptr and fptr to point into iregs and fregs after the arguments that
// correspond to 'arg' and those before it. spptr points into the stack space
// used for arguments after regs run out
}
inline _builtin_va_arg(va_list &ap, type) {
if (type is integer or pointer) {
if (ap->iptr == ap->iregs+8) {
rv = *(type *)ap->spptr;
ap->spptr += sizeof(type);
} else {
rv = *ap->iptr++;
}
} else if (type is float or double) {
if (ap->fptr == ap->fregs+8) {
rv = *(type *)ap->spptr;
ap->spptr += sizeof(type);
} else {
rv = *ap->fptr++;
}
} else {
// some other type (struct?) deal with it
}
}
请注意,这两个_builtin_va
函数都不能用C编写;它们需要内置到编译器中
https://stackoverflow.com/questions/15712760
复制