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

C/C++ need for local functions prototypes?

本文关键字:函数 原型 C++      更新时间:2023-10-16

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答案和评论。

除了需要作为前向参考时,声明本地(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);

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

考虑这些不执行任何特别有用的函数:

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. 您可以在一个视图中看到文件提供了哪些函数以及如何调用它们。

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

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

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

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

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