例如,
if(!function() { return false; }) {
console.log("False");
} else {
console.log("True");
}
输出:
#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");
}
此代码编译良好(没有使用clang的警告)并且运行良好。但我想知道传递给foo() is called
foo() is called
foo() is called
的值会发生什么变化?他们被推入堆栈还是被丢弃?
也许这个问题听起来毫无用处,但确实有道理。例如,当我有foo()
而不是int main()
并向其传递一些命令行参数时,int main(void)
的行为是否会受到影响?
此外,使用main()
时,ISO <stdarg.h>
之前至少需要一个命名参数。我们是否可以使用...
之类的声明来传递函数的零到无限参数?
我注意到void foo()
是一个&#34;非原型声明&#34;并且void foo()
是&#34;原型声明&#34;现在。这有点相关吗?
澄清
似乎这个问题被标记为What does an empty parameter list mean? [duplicate]的重复(有趣的是,这个问题也是重复的......)。事实上,我认为我的问题与那个问题无关。它侧重于&#34; C {#1}中的void foo(void)
意味着什么,但我知道这意味着&#34;我可以将任意数量的参数传递给它&#34;,我也知道它&#39;这是一个过时的功能。
但这个问题完全不同。关键字是&#34;如果&#34;。我只是想知道我是否向void foo()
传递了不同数量的参数,就像上面的示例代码一样,它们可以在void foo()
中使用吗?如果是这样,这是怎么做到的?如果没有,传递的参数会有什么不同吗?这是我的问题。
答案 0 :(得分:2)
在C中,void foo()
声明一个带有未指定数量参数的函数。以下列方式声明function:
return-type function-name(parameter-list,...) { body... }
parameter-list
是函数以逗号分隔的参数列表。如果没有给出参数,那么该函数不带任何参数,应该用空的括号或用关键字void定义。如果参数列表中的变量前面没有变量类型,则假定为int。
答案 1 :(得分:1)
正如Jonathan Leffler所说,C的调用约定确定调用函数(不是被调用函数)负责从堆栈中弹出参数,因此即使参数与参数不匹配,程序也不会崩溃被称为函数期望。
我补充说C的调用约定也确定参数以相反的顺序被压入堆栈(即调用foo (1, 2)
推送2
然后{{1 }})。这允许被调用函数访问第一个参数,即使它不知道其余参数。例如,即使不知道已传递了哪些其他参数,声明为1
的函数也能够访问int foo (int a, int b, ...)
和a
:b
和a
只是在堆栈顶部。访问其他参数需要堆栈指针黑客,这正是b
所做的。当然,通过使用不同的参数(例如printf
),可以轻松获得有趣的结果。
因此,根据问题,是的,printf ("%d%d", 3.5);
可以使用任何数量/类型的参数安全地调用,并且在1980年代,它将被视为&#34;正常实践&#34;使用堆栈上的指针hacks来访问未知参数。当可移植性和可读性变得越来越受关注时,int foo ()
作为实现这些指针攻击的可移植方式出现(编译器将为目标平台生成正确的代码,因此它不再是&#34;劈&#34)。但是,正如所述,<stdarg.h>
至少需要一个参数,因此无法帮助<stdarg.h>
。