繁体   English   中英

函数声明有多重要?

[英]How important is function declaration?

当我浏览书籍和网站时,写到函数声明/原型是必须的,但是当我在不声明的情况下运行程序时,它也会给我正确的结果。

你能解释为什么吗?

(我说的是函数的定义不在调用它的函数之前,因此函数定义不能提供有关原型的信息。如果不是这种情况,则声明该函数不是强制性的,但是仍然被认为是一种好习惯,因为它不依赖于函数定义的顺序,并且当一个顺序改变时,它更不容易出错。

函数声明很重要,因为调用约定 (平台的ABI的一部分)可以根据函数返回并接受作为参数的类型为参数定义不同的位置并返回值。 例如,通常将返回(足够大)结构的函数的返回值放在堆栈上,而返回int函数通常使用CPU寄存器作为返回值。 没有函数原型,大多数编译器都假定函数返回int ,这可能是错误的。 考虑以下示例:

// in a separate implementation file
struct foo {
    long long bar;
    char buf[128];
};

struct foo function()
{
    struct foo f = { 0 };
    return f;
}

// in another file - the implementation is invisible here,
// and in the lack of a prototype, the compiler assumes an integer return value
int x = function();

现在这可能会使堆栈混乱,因为该函数将返回值压入堆栈,但是赋值并不会弹出它,因为它采用了整数返回值。

在某种程度上,这取决于您的代码符合哪个标准。 标准前编译器非常松懈,因为它们根本不支持原型。 C89标准引入了原型,但是必须允许已经存在的大量代码进行编译。 因此,原型是可选的(从技术上讲,对于诸如支持可变数量参数的printf()函数除外;对于这些原型,即使在编译器通常不会抱怨或引起麻烦的情况下,即使声明是失踪)。

对于C99(和C2011),应该在使用每个函数之前为每个函数创建一个原型声明。 在定义每个非静态函数之前,最好先使其具有一个可见的原型声明。 该声明应位于使用该函数的其他文件可以包含的标头中。 标头充当“裁判”; 它确保使用该函数的代码具有正确的声明信息,并且确保定义该函数的代码与其他所有正在使用的声明匹配。

通常,除非将编译器推入严格模式,否则它将努力接受程序。 在GCC中添加-std=c99 -pedantic -Wall -Wextra等选项将启用许多警告。 值得在这些选项下干净地编译代码。

如果您使用的是GCC,则可以添加警告更多选项,以确保您收到有关遗漏的通知。 根据GCC的版本,您可以使用:

  • -Wmissing-prototypes (如果没有原型,则警告您)
  • -Wstrict-prototypes (警告您非原型,例如extern int func();
  • -Wold-style-declaration (警告您有关“ old style”,K&R,非原型声明的信息)
  • -Wold-style-definition (警告您有关“ old style”,K&R,非原型定义的信息)

我已经使用前两个了很久了。 所有的GCC 4.x甚至3.x系列编译器都支持它们。 后两个我是在去年左右才遇到的。 GCC 4.7.x支持它们,但GCC 4.1.x不支持(4.5.1支持它们;这是我手边的4.1.2以外的最旧的版本)。

GCC 4.7.x具有有用的选项: gcc --help=warnings 它以简单的摘要列出了它支持的所有警告:

...
-Wmissing-prototypes        Warn about global functions without prototypes
...
-Wold-style-declaration     Warn for obsolescent usage in a declaration
-Wold-style-definition      Warn if an old-style parameter definition is used
...
-Wstrict-prototypes         Warn about unprototyped function declarations
...

使用函数声明/原型是一种很好的做法/设计(不需要时)。

在很多情况下,您没有选择的余地,否则代码将很难维护。

  • 对于只有一个.c文件的程序,如果不使用原型,则必须按正确的顺序将函数排序到.c文件中

    =>函数的原型必须在您在代码中使用函数描述之前声明。

  • 当您需要编写更大的程序时,可以将代码分成单独的模块。 每个模块将具有“公开”和“私有”功能。 后者将被声明为静态(您仍然需要在.c文件顶部添加原型),并且'public'函数原型将放入.h文件中(标题)

只要函数实现位于函数调用之前,代码就可以在没有单独的函数声明的情况下运行,因为函数已由实现本身声明。 通常,尤其是对于largre程序,应为任何函数声明。

仅当在函数描述之前在代码中使用该函数时,才必须声明该函数的原型。

函数声明对于使编译器尽快检测数据类型问题很有用。 如果创建一个需要float的函数,而不是传递一个char ,则在某些情况下(例如,用于比较)它可能仍然可以工作,并且当您开始在其之上构建代码时会中断。 最后,计算机将所有内容都表示为一个位数组,因此您可以“求和”两个字符或将包含\\0两个整数连接起来,就好像它们是字符串一样,但是将来会使程序变得一团糟。

由于程序的编译是从上到下(即第一行到最后一行)进行的,因此需要函数声明(也称为前向声明)。

仅当函数调用在函数实现之前时才需要。

最好向编译器提及在此声明的函数已在程序中的某处使用。

声明也可以在用户定义的头文件中完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM