【问题标题】:C/C++ need for local functions prototypes?C/C++ 需要本地函数原型吗?
【发布时间】:2013-10-22 09:04:01
【问题描述】:

在 C/C++ 中显式原型化本地函数有什么好处,而不是在使用之前定义函数?本地我的意思是函数仅在其源文件中使用。一个例子是这样的:

#include "header.h"

static float times2(float x){
    return 2*x;
}

static float times6(float x){
    return times2(3*x);
}

int main(void){

    // Other stuff ...

    float y = times6(1);

    // Other stuff ...
}

相对于这个:

#include "header.h"

// Local function prototypes
static float times2(float);
static float times6(float);

// Main
int main(void){

    // Other stuff ...

    float y = times6(1);

    // Other stuff ...
}

// Local functions definition
static float times2(float x){
    return 2*x;
}

static float times6(float x){
    return times2(3*x);
}

我个人更喜欢使用第一个选项,因为要编写的代码更少并且(对我而言)文件更易于阅读,但现在我想知道是否有任何技术原因更喜欢第二个选项。

编辑:我在 times2() 和 times6() 中添加了 static,请参阅@Gangadhar 答案和下面的 cmets。

【问题讨论】:

  • 唯一的技术原因是它们是否相互引用。除此之外,这一切都归结为风格。
  • 你应该把你的“本地人”放到一个匿名的命名空间中,这样他们就不会得到外部链接。
  • @nijansen:你能发表你的评论作为答案吗? (您是第一个指出交叉引用案例的人,也是唯一一个明确指出否则没有技术理由使用选项 1 的人。对我来说,这就是问题的答案。)
  • @Milo 我已经添加了一个答案,但我仍然希望鼓励您选择您认为最有帮助的答案。

标签: c++ c function-prototypes


【解决方案1】:

除了需要作为前向引用之外,声明本地 (statc) 函数的优点是组织性。同样的道理也适用于静态变量。

如果一个文件有几十个函数(和变量),前面的本地定义有助于组织。人们可能希望按顺序(A-Z)保持如此大的集合。此命令可能/可能不适用于前向引用。通过列出所有函数/变量(在 (*.h` 文件中的全局变量)和在此处 (*.c) 中的局部变量),可以维护组织,即使 前向引用需求可能在生命周期内发生变化的代码。

// function/variable prototypes
static float pi;
static float pi2;
static float times2(float);
static float times3(float);
static float times4(float);
static float times5(float);
static float times6(float);
static float times7(float);
static float times8(float);
static float times9(float);

【讨论】:

    【解决方案2】:

    在某些情况下,您需要事先声明函数原型,即编译器需要知道函数原型才能使用该函数。

    考虑这些没有什么特别有用的功能:

    int foo(int x)
    {
        if(x < 1) return x;
        else return x + bar(x-1);
    }
    
    int bar(int x)
    {
        if(x < 3) return x;
        return x * foo(x-1);
    }
    

    如果你尝试编译它,编译器会生你的气:

    错误:“bar”未在此范围内声明

    你需要把缺失的原型放在使用它的函数前面:

    int bar(int);
    // as above unchanged
    

    这是编译器要求您在函数之前放置函数原型的唯一情况。在所有其他情况下,将原型随意放置在任何地方都是完全合法的,因此这也是合法的:

    int foo(int);
    int bar(int);
    int foo(int);
    int bar(int);
    

    虽然显然是多余的(请不要这样做)。有些人认为将文件中每个函数的函数原型放在文件顶部是一种很好的风格,因为

    1. 您不必关心编译器要求您再执行此操作的情况,有些人显然无法解释编译器的错误消息(我认为这非常简洁),并且
    2. 您可以在一个视图中看到文件提供了哪些函数以及如何调用它们。

    但这正是风格讨论。我喜欢让我的代码尽可能短,所以我只会使用编译器需要的原型,但这纯粹是一个品味和惯例的问题。在罗马时,像罗马人那样做。

    【讨论】:

    • 感谢您的回答。问题不在于风格,我只是想确保使用选项 1(这是我自己更喜欢的风格)没有技术副作用。
    【解决方案3】:

    如果提到原型:函数times2,times6在调用时期望浮点参数在堆栈或寄存器中。如果省略原型,编译器将无法强制执行此操作,并且上述函数最终将操作堆栈上的其他一些数据。通过包含函数原型,您可以告知编译器这两个函数都采用一个浮动参数,并让编译器能够捕获此类错误。

    【讨论】:

    • 虽然理论上很好,但实际上我从未见过 C++ 编译器甚至允许使用在调用站点之前尚未在翻译单元中声明的函数。我猜标准不允许这样做,尽管我可能是错的。
    • 这个答案给出了在使用之前声明函数在范围内的原因。但这不是问题。问题是在使用前只有一个声明或在使用前有定义(这也是一个声明)。在这两种情况下,声明都在使用前的范围内。
    【解决方案4】:

    当两个函数相互调用时,即 FuncA() 调用 FuncB(),反之亦然,则必须声明其中任何一个函数。这是@M M(以上答案)描述的条件。

    但在任何正常情况下,声明函数只是一种约定,因开发者而异。

    【讨论】:

      【解决方案5】:

      必需的前向引用和外部是使用原型的唯一原因。原型是噪音。在使用之前声明函数。它更干净,只需要您更改一次界面。我不明白人们为什么要使用它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-02
        • 1970-01-01
        • 2011-06-22
        • 1970-01-01
        • 2011-02-04
        • 2013-04-12
        • 2011-06-19
        • 2010-12-06
        相关资源
        最近更新 更多