【问题标题】:int foo (int argc, ...) vs int foo() vs int foo(void) in CC 中的 int foo (int argc, ...) vs int foo() vs int foo(void)
【发布时间】:2012-04-04 18:46:30
【问题描述】:

所以今天我想(承认第一次)int foo() 实际上与 int foo(void) 不同,因为第一个允许 任何 数量的输入,而第二个允许

int foo() 会忽略任何给定的输入吗?如果是这样,允许这种形式的功能有什么意义?如果没有,您如何访问它们?这与拥有可变参数列表(例如 int foo (int argc, ...) 之类的东西)有何不同?

【问题讨论】:

标签: c arguments argument-passing


【解决方案1】:

在符合标准的 C 中,如果函数不接受任何参数,则必须使用 int foo(void)

我猜当您将参数传递给带有空括号的函数时,会发生什么取决于编译器。但我认为没有办法访问这些参数。

至于 main,编写它们的唯一标准符合(纯 c)方法是 int main(void)int main(int argc, char **argv)(或相同的 char *argv[])。

【讨论】:

  • 在标准里查了一下,好像空大括号也声明了一个不带参数的函数。编写 (void) 以明确声明您不期望任何参数通常是一个很好的约定。如果您还有类似的问题,最好阅读标准的内容(以及您的实现文档,即 gcc、glibc...)。您可以在线免费找到标准草案。
【解决方案2】:

理解这一点的关键是理解调用堆栈。当您在 C 中调用函数(使用标准 x86 ABI - 其他平台可能会有所不同)时会发生什么情况,即调用者在调用被调用者之前将所有参数以相反的顺序压入堆栈。然后,被调用者可以根据需要读取任意数量的这些参数。如果您使用 foo(void),显然您不会阅读任何内容。如果您使用 foo(int),您将能够将一个单词读入当前帧下方的堆栈中。

使用 foo()(没有指定参数)意味着编译器不会检查你传递给 foo 的参数。什么都行;没有合同。如果 foo 有两个不同的实现将不同的类型作为参数,并且我希望能够以编程方式将它们切换出来,这将很有用。 (在汇编程序中编写函数时,它有时也很有用,您可以自己处理堆栈和参数。)但请记住,编译器不会为您进行任何类型检查,因此您必须非常小心。

这与 foo(int, ...) 不同,因为在这种情况下,函数实际上可以访问所有参数(使用 varargs)。没有理由用 foo() 实际定义 一个函数,因为它基本上等同于 foo(void)。 foo() 只对声明有用。

【讨论】:

  • 我要添加到第一段的唯一一件事是调用者然后将参数从堆栈中弹出(嗯......增加esp),而不是被调用者。这很重要,因为它不适用于被调用者清理。
【解决方案3】:

首先,取int foo()。这种形式是一个不提供 prototype 的函数声明——也就是说,它不指定其参数的数量和类型。它是一种古老的函数声明形式——它是函数最初在 ANSI C 之前声明的方式。然而,这样的函数 具有 固定数量和类型的参数——只是声明没有告诉编译器它是什么,所以你有责任在你调用函数的地方把它弄好。您使用如下参数声明这样的函数:

int foo(a, b)
    int a;
    char *b;
{
    return a + strlen(b);
}

这种形式的函数声明现在已经过时了。

int foo(void) 是提供原型的现代声明;它声明了一个不带参数的函数。 int foo(int argc, ...)也提供了原型;它声明了一个具有一个固定整数参数和一个可变参数列表的函数。

【讨论】:

    【解决方案4】:

    嗯,在 C++ 中,这两种形式是等价的,它们都声明了一个不带参数的函数。如果你尝试调用函数并传入一个参数,编译会报错。

    另一方面,C 和 Objective-C 都以不同的方式处理这两种形式。在这些语言中,第一种形式声明了一个接受未知数量参数的函数,而第二种形式声明了一个根本不接受任何参数的函数。因此,在 C 中,以下是有效代码:

    int foo() {
      return 5;
    }
    int main() {
      return foo(1, 2, 3);
    }
    

    编译器不会报错,代码运行良好(C++ 编译器会在相同的代码上报错)。

    通常,您希望在 C 和 Objective-C 中使用第二种形式并包含显式 void 以指示函数不应带参数。但是,在 C++ 中更常见的是使用第一种形式,因为它等效且更短。

    【讨论】:

      猜你喜欢
      • 2020-06-16
      • 1970-01-01
      • 1970-01-01
      • 2011-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多