如果我声明一个带有空参数表的函数,然后将参数传递给它怎么办?

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() 的行为会受到影响吗?

另外,当使用&lt;stdarg.h&gt; 时,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() 宏需要最后一个命名参数的名称——如果没有命名参数,它可以不行。 你说得对,&lt;stdarg.h&gt; 至少需要一个参数。这就是为什么我想知道是否可以使用()。 BTW:这个问题我已经说清楚了,你能看一下吗? 值被压入堆栈;当函数返回时,调用函数会清除堆栈(这是 C 调用约定;其他语言使用不同的约定,因为被调用函数知道它传递了多少参数,或者使用了多少参数空间来传递它的参数,并且因此可以清除堆栈)。没有可移植的方式来使用传递给函数的参数,例如 foo() 否;没有任何意义。你甚至可能认为这是无稽之谈。 @JonathanLeffler;我不认为这是一个骗局。 【参考方案1】:

正如 Jonathan Leffler 所说,C 的调用约定规定调用函数(不是被调用函数)负责从堆栈中弹出参数,因此即使参数与被调用函数所期望的不匹配,程序也不会崩溃。

我要补充一点,C 的调用约定还规定参数以相反的顺序压入堆栈(即调用foo (1, 2) 压入2,然后压入1)。这允许被调用函数访问第一个参数,即使它不知道其余参数。例如,声明为int foo (int a, int b, ...) 的函数将能够访问ab,即使不知道传递了哪些其他参数:ab 就在堆栈顶部。访问其他参数将需要堆栈指针 hack,这正是 printf 所做的。当然,通过使用与预期不同的参数(例如,printf ("%d%d", 3.5);),可以轻松获得有趣的结果。

因此,根据问题,是的,int foo () 可以使用任意数量/类型的参数安全地调用,并且在 1980 年代,使用堆栈上的指针破解来访问未知参数被认为是“正常做法” .当可移植性和可读性越来越受到关注时,&lt;stdarg.h&gt; 作为实现这些指针 hack 的可移植方式出现(编译器将为目标平台生成正确的代码,因此不再是“hack”)。但是,正如上面所说,&lt;stdarg.h&gt; 至少需要一个参数,所以它对int foo () 没有帮助。

【讨论】:

【参考方案2】:

在 C 中,void foo() 声明了一个接受未指定数量参数的函数。 function 的声明方式如下:

return-type function-name(parameter-list,...)  body... 

parameter-list 是函数采用逗号分隔的参数列表。如果没有给定参数,则该函数不带任何参数,应使用空括号集或关键字 void 定义。如果参数列表中的变量前面没有变量类型,则假定为 int。

【讨论】:

以上是关于如果我声明一个带有空参数表的函数,然后将参数传递给它怎么办?的主要内容,如果未能解决你的问题,请参考以下文章

Bash:将带有空变量的“$@”参数传递给 sudo -i

如何将带有 args 的成员函数作为参数传递给另一个成员函数?

将命令行参数传递给调用带有装饰器参数的装饰函数的函数

将任意数量的参数传递给Javascript函数[重复]

Java:将具有不同类型的参数传递给函数

将对象作为参数传递给函数