如果我声明一个带有空参数表的函数,然后将参数传递给它怎么办?
Posted
技术标签:
【中文标题】如果我声明一个带有空参数表的函数,然后将参数传递给它怎么办?【英文标题】:What if I declare a function with empty parameter table, then pass arguments to it? 【发布时间】:2016-05-27 08:40:46 【问题描述】:例如,
#include <stdio.h>
void foo();
int main(void)
foo();
foo(42);
foo("a string", 'C', 1.0);
return 0;
void foo()
puts("foo() is called");
输出:
foo() is called
foo() is called
foo() is called
这段代码编译良好(没有使用 clang 的警告)并且运行良好。但我想知道传递给foo()
的值会发生什么?它们是被推入堆栈还是被丢弃?
也许这个问题听起来没用,但确实有道理。例如,当我有int main()
,而不是int main(void)
,并将一些命令行参数传递给它时,main()
的行为会受到影响吗?
另外,当使用<stdarg.h>
时,ISO C 在...
之前至少需要一个命名参数。我们是否可以使用void foo()
这样的声明来传递从零到无限的参数给一个功能?
我注意到void foo()
是一个“非原型声明”,而void foo(void)
是一个“原型声明”。这有点相关吗?
澄清
似乎这个问题被标记为与What does an empty parameter list mean? [duplicate]重复(有趣的是,那个问题也是重复的......)。事实上,我认为我的问题与那个问题无关。它侧重于“void foo()
在 C 中的含义”,但我知道这意味着“我可以向它传递任意数量的参数”,而且我也知道这是一个过时的功能。
但这个问题完全不同。关键词是“如果”。我只想知道我是否将不同数量的参数传递给void foo()
,就像上面的示例代码一样,它们可以在foo()
中使用吗?如果是这样,这是如何完成的?如果不是,传递的参数有什么不同吗?这是我的问题。
【问题讨论】:
请注意,您不能使用无参数函数来传递零个或多个变量参数,因为va_start()
宏需要最后一个命名参数的名称——如果没有命名参数,它可以不行。
你说得对,<stdarg.h>
至少需要一个参数。这就是为什么我想知道是否可以使用()
。 BTW:这个问题我已经说清楚了,你能看一下吗?
值被压入堆栈;当函数返回时,调用函数会清除堆栈(这是 C 调用约定;其他语言使用不同的约定,因为被调用函数知道它传递了多少参数,或者使用了多少参数空间来传递它的参数,并且因此可以清除堆栈)。没有可移植的方式来使用传递给函数的参数,例如 foo()
。
否;没有任何意义。你甚至可能认为这是无稽之谈。
@JonathanLeffler;我不认为这是一个骗局。
【参考方案1】:
正如 Jonathan Leffler 所说,C 的调用约定规定调用函数(不是被调用函数)负责从堆栈中弹出参数,因此即使参数与被调用函数所期望的不匹配,程序也不会崩溃。
我要补充一点,C 的调用约定还规定参数以相反的顺序压入堆栈(即调用foo (1, 2)
压入2
,然后压入1
)。这允许被调用函数访问第一个参数,即使它不知道其余参数。例如,声明为int foo (int a, int b, ...)
的函数将能够访问a
和b
,即使不知道传递了哪些其他参数:a
和b
就在堆栈顶部。访问其他参数将需要堆栈指针 hack,这正是 printf
所做的。当然,通过使用与预期不同的参数(例如,printf ("%d%d", 3.5);
),可以轻松获得有趣的结果。
因此,根据问题,是的,int foo ()
可以使用任意数量/类型的参数安全地调用,并且在 1980 年代,使用堆栈上的指针破解来访问未知参数被认为是“正常做法” .当可移植性和可读性越来越受到关注时,<stdarg.h>
作为实现这些指针 hack 的可移植方式出现(编译器将为目标平台生成正确的代码,因此不再是“hack”)。但是,正如上面所说,<stdarg.h>
至少需要一个参数,所以它对int foo ()
没有帮助。
【讨论】:
【参考方案2】:在 C 中,void foo()
声明了一个接受未指定数量参数的函数。 function 的声明方式如下:
return-type function-name(parameter-list,...) body...
parameter-list
是函数采用逗号分隔的参数列表。如果没有给定参数,则该函数不带任何参数,应使用空括号集或关键字 void 定义。如果参数列表中的变量前面没有变量类型,则假定为 int。
【讨论】:
以上是关于如果我声明一个带有空参数表的函数,然后将参数传递给它怎么办?的主要内容,如果未能解决你的问题,请参考以下文章