我有一个很棘手的问题,我今天一直在玩,但是我还不能提出一个优雅的解决方案。
我们知道,void func()
形式的函数接受无限多个参数。现在,我整理了一个非常简单的最小工作代码段:
#include <stdio.h>
int func()
{
printf("%d, %d, %d, %d\n");
return 0;
}
int func() {
sucks(0 /* Offset */, 1, 2, 3, 4);
}
好的,我们现在可以根据需要调用任意数量的func()了。我正在试验atm的问题是:我们如何才能正确访问这些参数的内容? printf()函数打印出类似这样的内容……只是为了向我们自己验证参数是否确实存在:
anonymous@melina:/tmp$ ./a.out
1 2 3 4
所以现在是一个问题:上面的代码片段有些黑。是否有访问这些参数的正确方法?或者,您是否真的需要弄乱堆栈指针和内联汇编?第一次尝试时,我曾想过要在函数的开头获取堆栈指针,例如
uint64_t sp;
asm( "mov %%rsp, %0" : "=rm" ( sp ));
...并以某种方式使用它来猜测这些参数实际上在内存中的位置。但是……到目前为止我还没有成功。
答案 0 :(得分:6)
是否有访问这些参数的正确方法?
是的。在函数定义中指定参数列表以及函数的类型和标识符。
您可以按“旧样式”进行操作(不要这样做,不应在新代码中使用它):
int func(a, b, c, d)
int a;
int b;
int c;
int d;
{
printf("%d %d %d %d\n", a, b, c, d);
}
或正常:
int func(int a, int b, int c, int d) {
printf("%d %d %d %d\n", a, b, c, d);
}
或使用stdarg.h:
int func(int a, ...) {
va_list ap;
va_start(va, a);
int b = va_arg(va, int);
int c = va_arg(va, int);
int d = va_arg(va, int);
printf("%d %d %d %d\n", a, b, c, d);
va_end(ap);
}
或使用第二个arg中的stdarg.h:
int func(int a, int b, ...) {
va_list ap;
va_start(va, b);
int c = va_arg(va, int);
int d = va_arg(va, int);
printf("%d %d %d %d\n", a, b, c, d);
va_end(ap);
}
或使用第三个arg中的stdarg.h:
int func(int a, int b, int c, ...) {
va_list ap;
va_start(va, c);
int d = va_arg(va, int);
printf("%d %d %d %d\n", a, b, c, d);
va_end(ap);
}
stdarg.h
至少需要声明参数列表中的第一个参数。因此,没有办法处理带有未指定数量和参数类型的函数,但是有一种方法(stdarg.h
)处理带有至少1个参数后跟未指定数量和参数类型的函数。
...形式为void
func()
的函数接受无限多个参数
这不是事实。我认为没有C标准的方法可以将无数个参数传递给函数。
格式为func()
的函数采用 unspecified 的数量和类型的参数。它们采用有限数量的参数,但是在遇到此类函数声明的事务单元中未指定数量。如果函数定义带有5个参数,则它们带有5个参数,否则为未定义的行为。如果函数定义采用省略号(,...)(在这种情况下为no information about the number or types of the parameters after the comma is supplied.
(C11 6.7.6.3p9),则不指定参数的数量。
还是您必须真正弄乱堆栈指针和内联汇编?
是的,您必须“困惑”于实现定义的行为。
... va_start的ISO实现带有另一个第二个参数。用户应该在此处编写该函数的最后一个命名参数。
但是,va_start不应使用此参数。
您需要为va_start
指定第二个参数。也许可以在this thread中找到有关该主题的更多信息。
printf(“%d%d%d%d \ n”);
这是未定义的行为。程序具有未定义的行为后,请nasal demons start spawning in your room and are fighting for independence。它可能在您的平台或实现上具有明确定义的行为,但这是错误的,它不再是C语言。 this thread中的If there is a "correct" behavior according to your mental model of the language, that model is simply wrong;
。从语言的角度来看,鼻恶魔为独立而战,该程序无效。
答案 1 :(得分:1)
[...]形式为void func()的函数接受无限多个参数。
不。
必须在没有原型的情况下使用功能 。
void foo(); // not a prototype
int main(void) {
// foo() must be called according to its definition
foo(12, 4, "bar", -42); // error (undetected by compiler)
foo("---", 12, 4, "bar", -42); // no error
}
void foo(const char *msg, int n, ...) { /* ... */ }
请注意,C89之前的函数定义具有不同的参数定义方式。向后兼容性的愿望仍然允许这种语法。我相信上述限制同样适用
void bar() /* pre-C89 syntax */
const char *msg;
int n;
{ /* ... */ }