int max(int n, ...)
我使用cdecl
调用约定是主叫被叫返回后清理变量。
我想知道怎么做宏va_end
, va_start
并va_arg
工作?
是否呼叫者传递的参数数组作为第二个参数为最大的地址?
int max(int n, ...)
我使用cdecl
调用约定是主叫被叫返回后清理变量。
我想知道怎么做宏va_end
, va_start
并va_arg
工作?
是否呼叫者传递的参数数组作为第二个参数为最大的地址?
如果你顺便看看C语言存储堆栈,宏工作应该成为开道的参数: -
Higher memory address Last parameter
Penultimate parameter
....
Second parameter
Lower memory address First parameter
StackPointer -> Return address
(注意,这取决于硬件堆栈指针也许一个线向下和更高和更低的可以被交换)
这些参数总是存储这样1,即使没有...
参数类型。
该va_start
宏只设置了一个指向第一个功能参数,例如: -
void func (int a, ...)
{
// va_start
char *p = (char *) &a + sizeof a;
}
这使得p
点到第二参数。 将va_arg
宏做到这一点: -
void func (int a, ...)
{
// va_start
char *p = (char *) &a + sizeof a;
// va_arg
int i1 = *((int *)p);
p += sizeof (int);
// va_arg
int i2 = *((int *)p);
p += sizeof (int);
// va_arg
long i2 = *((long *)p);
p += sizeof (long);
}
该va_end
宏仅设置p
值为NULL
。
笔记:
...
参数将使用栈这种能力和编译器开关。 作为参数在栈上通过, va_
“功能”(他们最作为宏实现的时间),只需操纵的堆栈指针。 这家私人堆栈指针从传递给参数存储va_start
,然后va_arg
“啪啪”,从“堆栈”的参数,因为它迭代的参数。
比方说,你调用该函数max
有三个参数,如下所示:
max(a, b, c);
里面的max
功能,堆栈基本上是这样的:
+-----+ | c | | b | | a | | ret | SP -> +-----+
SP
是真正的堆栈指针,它是不是真的a
, b
和c
的堆栈但它们的值上。 ret
是返回地址,在跳的时候,该功能是为了。
什么va_start(ap, n)
作用是把参数的地址( n
在你的函数原型),然后在计算一个参数的位置,所以我们得到了一个新的专用堆栈指针:
+-----+ | c | ap -> | b | | a | | ret | SP -> +-----+
当您使用va_arg(ap, int)
返回什么私人堆栈指针指向,然后通过改变私人堆栈指针现在在一个参数指向“弹出”它。 堆栈现在这个样子:
+-----+ ap -> | c | | b | | a | | ret | SP -> +-----+
这说明当然是简化的,但显示的原则。
一般地,我怎么神交target.def,当一个函数原型声明了(...)编译器设置标有可变参数标志,并且引用类型的命名参数解析树。 对于严格的C标准的每个命名参数应该得到任何额外的信息是必要的附加设置的va_list时参数的va_start的命名字段,作为一个可能的返回va_arg的(),但大多数编译器只是产生了最后一个命名参数此信息。 当定义函数将其序言发生器注意到可变参数标志设置,并增加了必要设置任何隐藏的字段将其添加到具有已知偏移va_start宏可以引用帧的代码。
当它发现它创建为每个参数表示...,可能引入的运行时类型信息附加隐藏字段,诸如数组边界,即附加到字段设置为的va_start附加解析和代码生成树木功能的基准va_arg函数和对命名参数。 这种组合的树确定代码被生成的内容的参数值复制到所述框架,所述序幕设置什么是必要的va_start创建开始在任意或最后命名的参数的va_list,和在va_arg()的每个调用生成的内联代码的引用用于在编译时,以验证任何参数特定隐藏字段预期收益分配与使用的表达被编译兼容,并执行任何所需的参数提升/强制转换。 指定字段值的大小和隐藏字段大小的总和决定了什么样的价值编译调用后,或者函数尾声的被叫清理模式,在返回来调整框架。
每个步骤具有处理器和调用约定的依赖关系,封装在配置的/ proc / proc.c和proc.h文件,则重写简单化默认的va_start的)),该假设每个参数定义(和在va_arg(具有固定的大小分配一个堆栈中的第一命名参数上方一定距离。 对于作为分开的malloc()秒中实现一些平台或语言参数帧比一个固定大小的堆栈更加理想。 还要注意这些用法不是线程安全的; 是不安全的传递的va_list参照另一个线程,而不在保证参数帧未指定的装置不进行无效的,由于函数返回或线程的中止。
int max(int n, const char *msg,...)
{
va_list args;
char buffer[1024];
va_start(args, msg);
nb_char_written = vsnprintf(buffer, 1024, msg, args);
va_end(args);
printf("(%d):%s\n",n,buffer);
}