【问题标题】:Why do function prototypes include parameter names when they're not required?为什么函数原型在不需要时包含参数名称?
【发布时间】:2011-07-11 04:31:10
【问题描述】:

我一直认为函数原型必须包含函数的参数及其名称。但是,我只是尝试了一下:

int add(int,int);

int main()
{
    std::cout << add(3,1) << std::endl;
}

int add(int x, int y)
{
    return x + y;
}

它奏效了!我什至尝试过极其谨慎地编译:

g++ -W -Wall -Werror -pedantic test.cpp

它仍然有效。所以我的问题是,如果你不需要函数原型中的参数名称,为什么这样做如此普遍?这有什么目的吗?和函数的签名有关系吗?

【问题讨论】:

  • 我认为如果原型中包含参数名称,可读性会更好。
  • 它究竟是如何增加可读性的?
  • 在您的情况下,您有两个int 参数,没有名称如何知道是先传入x 还是y
  • 在具有晦涩参数名称的函数中(如 x 和 y),将它们写在原型中有何不同?
  • add 函数中参数的顺序并不重要,并且大多数人已经知道名为“add”的函数会将其参数添加到一起,而不会对值赋予意义,所以名称在这个例子中并不重要。但是考虑像strstr 这样的函数。顺序很重要。哪个参数先出现?如果参数具有独特的名称,例如needlehaystack,以及您的编辑器是否会在您编写代码或报告错误时向您显示这些名称,是否更容易记住? 这就是可读性。

标签: c++ naming function-prototypes


【解决方案1】:

不,这些不是必需的,编译器大多会忽略。你甚至可以在不同的声明中给他们不同的名字;以下是完全合法的:

int foo(int bar);
int foo(int biz);
int foo(int qux) {
    ...
}

(编译器会检查每个名称在同一个参数列表中只使用一次:int foo(int bar, int bar); 被拒绝。)

放入它们的原因是文档:

  • 如果有人读了你的头文件,他们一眼就能看出每个参数的用途。
  • 如果您使用花哨的 IDE,它可以在您开始键入函数调用时显示参数名称。
  • Doxygen 等文档工具可以解析参数名称并将其显示在文档中。

【讨论】:

    【解决方案2】:

    参数名称是完全可选的,对编译没有影响。可以将它们放在那里以提高代码的可读性。

    【讨论】:

      【解决方案3】:

      声明中不需要参数名称。它们纯粹是文档。

      你甚至不需要定义中的名字:

      int f(int)
      {
          return 0;
      }
      

      在 C++ 中编译得很好(虽然不是在 C 中)。这有时对例如有用继承、重载、函数指针。

      【讨论】:

      • 如果定义使用该参数,您确实需要定义中的名称。
      • 您无法访问它。您可能至少会在两种情况下使用它:(1)为了向前兼容,以防您想稍后开始使用它而无需更新所有呼叫站点; (2) 当你重写一个虚方法,但不想检查参数时。
      • 在定义中省略未使用参数的名称通常还具有抑制编译器发出任何“未使用参数”警告的效果。
      • @MisterSir:在某些情况下,您有一个实际上并没有使用的参数。它仅用于重载决议。例如,参见 std::advance 函数。如果你命名参数,你会得到一个警告
      • @MisterSir 在某些情况下你不想访问它,特别是我们的老朋友 iterator::operator++(int) 其中 int 只是表示它是一个后增量运算符.
      【解决方案4】:

      您不需要在函数原型中包含参数名称。您只需要完整的签名,其中包括参数的类型和(在函数模板特化的情况下)返回值。

      但是,为了编写自记录代码,包含参数名称仍然很常见。也就是有这个声明的函数:

      void foo(int number_of_foos_desired, string foo_replacement);
      

      只看原型可能比这个更容易理解:

      void foo(int, string);
      

      当您编写调用此函数的代码时,许多现代 IDE 也会在您键入时弹出参数名称。如果原型中不包含参数名称,他们可能无法弹出此信息。

      【讨论】:

      • 我一直认为函数签名不包括它的返回类型(除非它是模板特化)
      • @Mister:通常是这样。但在函数模板特化的情况下,返回类型是签名的一部分。
      【解决方案5】:

      这与函数的签名有很大关系。

      使用 .h 文件的好处之一是,当有人出现并想了解您的程序/api 做了什么时,他们可以查看您的头文件并了解正在执行的操作,他们的输入和输出,一切如何结合在一起,等等。

      如果你遇到像

      这样的方法
      int doStuff(int,int)
      

      这比带有say签名的方法要少得多:

      int doStuff(int firstNumberToAdd, int secondNumberToAdd);
      

      通过第二个,您至少可以了解正在执行的操作以及正在发生的事情。这就是编写自我记录代码背后的想法。

      如果您有兴趣,可以查看 Steve McConnell 的 Code Complete。

      【讨论】:

      • 参数名称不是签名的一部分。
      【解决方案6】:

      它有不同的场景。我发现它对处理inheritancevirtual functions 很有帮助。如果您使用在子类中生成未使用警告的virtual function,则可以省略变量名。

      【讨论】:

        猜你喜欢
        • 2019-05-20
        • 1970-01-01
        • 2018-03-16
        • 1970-01-01
        • 1970-01-01
        • 2014-07-25
        • 1970-01-01
        • 2011-12-26
        • 1970-01-01
        相关资源
        最近更新 更多