C / C ++需要本地函数原型吗?

时间:2013-10-22 09:04:02

标签: c++ c function-prototypes

在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(),请参阅@Gangadhar回答和评论。

6 个答案:

答案 0 :(得分:3)

除非需要作为转发参考,否则声明本地(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);

答案 1 :(得分: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. 您在一个视图中看到文件提供了哪些功能以及如何调用它们。
  3. 但这正是风格讨论。我喜欢尽可能缩短我的代码,所以我只会使用编译器所需的原型,但这纯粹是品味和惯例的问题。在罗马时,做罗马人或类似的东西。

答案 2 :(得分:0)

如果你可以避免前瞻性声明,那么你的问题是意见基础,我没有任何建议。

但有时候你无法避免前瞻声明,例如:

void f();

void g()  { /* ... */  f();  }

void g()  { /* ... */  g();  }

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

必需的前向引用和extern是使用原型的唯一原因。原型就是噪音,使用前先声明功能。它更清洁,只需要您更改一次接口即可。我不明白为什么人们会使用它们。