c - 如果我声明一个参数表为空的函数,然后将参数传递给它会怎样?

标签 c parameters command-line-arguments declaration function-declaration

例如,

#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()是一个“非原型(prototype)声明”并且 void foo(void)刚才是一个“原型(prototype)声明”。这有点相关吗?


澄清

似乎这个问题被标记为重复What does an empty parameter list mean? [duplicate] (有趣的是,这个问题也是重复的......)。事实上,我不认为我的问题与那个问题有任何关系。它着重于“void foo() 在 C 中的含义”,但我知道这意味着“我可以向它传递任意数量的参数”,而且我也知道这是一个过时的功能。

但是这个问题是很不一样的。关键词是“如果”。我只想知道我是否将不同数量的参数传递给 void foo() , 就像上面的示例代码一样,它们可以在 foo() 内部使用吗? ?如果是这样,这是怎么做到的?如果不是,传递的参数有什么区别吗?这是我的问题。

最佳答案

正如 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 年代,在堆栈上使用指针 hack 来访问未知参数将被视为“正常做法”。当可移植性和可读性变得越来越受关注时,<stdarg.h>作为实现这些指针 hack 的可移植方式出现(编译器将为目标平台生成正确的代码,因此它不再是“hack”)。然而,正如所说,<stdarg.h>至少需要一个参数,所以它不能帮助 int foo () .

关于c - 如果我声明一个参数表为空的函数,然后将参数传递给它会怎样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35426282/

相关文章:

mysql - C客户端程序连接MySQL错误检测

c - 调整二维数组的大小,并将元素的平均值转移到 c 中较小的矩阵

c++ - 将预处理器宏定义到宏定义行

c - 如何将 char** 中的每个字符串打印到 printf()?

python - 在 python 2.6 脚本中执行从终端获取参数的终端命令

c - 进程页表

php - 如何在PHP中实现一个可以接受任意参数的函数?

sql-server - 当我使用 BeginExecuteNonQuery 时,我的输出参数始终为空

java - Java中的形式参数是什么?

bash - 检查传递给 Bash 脚本的标志和过程值