C编程中前向声明的意义是啥?

Posted

技术标签:

【中文标题】C编程中前向声明的意义是啥?【英文标题】:What is the significance of forward declaration in C programming?C编程中前向声明的意义是什么? 【发布时间】:2016-01-29 12:29:11 【问题描述】:

我现在正在通过 Zed A. Shaw 的 Learn C the Hard Way 学习 C 编程。有这段代码(取自他的网站):

#include <stdio.h>
#include <ctype.h>

// forward declarations
int can_print_it(char ch);
void print_letters(char arg[]);

void print_arguments(int argc, char *argv[])

    int i = 0;

    for(i = 0; i < argc; i++) 
        print_letters(argv[i]);
    


void print_letters(char arg[])

    int i = 0;

    for(i = 0; arg[i] != '\0'; i++) 
        char ch = arg[i];

        if(can_print_it(ch)) 
            printf("'%c' == %d ", ch, ch);
        
    

    printf("\n");


int can_print_it(char ch)

    return isalpha(ch) || isblank(ch);



int main(int argc, char *argv[])

    print_arguments(argc, argv);
    return 0;

难道我们就可以这样编码吗(将can_print_itprint_letters 函数放在顶部,无需前向声明):

#include <stdio.h>
#include <ctype.h>

int can_print_it(char ch)

    return isalpha(ch) || isblank(ch);


void print_letters(char arg[])

    int i = 0;

    for(i = 0; arg[i] != '\0'; i++) 
        char ch = arg[i];

        if(can_print_it(ch)) 
            printf("'%c' == %d ", ch, ch);
        
    

    printf("\n");

前向声明真的很重要且不可避免吗?

【问题讨论】:

“前向声明真的很重要且不可避免吗?” - 是的,一直,我并不是说你必须一直转发声明,但这是非常普遍和不可避免的,基本上每次你在两个对象之间有一个“循环关系”时,即使他们经常需要它在同一源中声明 如果func1 调用func2,而func2 调用func1 会怎样? (但重点是头文件和库。) 你的方法如何绕过这个?而不是使用“短方法签名”声明,而是在那里声明和定义整个函数。 想象一下你有一个更大的项目。将所有代码放在一个 .c 文件中绝对是一场噩梦,因此您通常会将其拆分为多个源文件。所以现在,要从b.c 中调用a.c 中定义的myFunc,您需要一个前向声明(通常在头文件中)。 哇,真的很多投入。由于我是初学者,我无法真正理解这里的所有论点,但我确实知道这有什么用处。谢谢。 【参考方案1】:

只要你的调用图是循环的,函数的前向声明是不可避免的;也就是说,只要您在函数之间进行(直接或间接)递归。

如果您想将程序分成多个翻译单元,它们很有用,因为它们允许分离声明和函数定义(将声明放在 .h 标头和定义中)在.c 文件中)。

【讨论】:

我知道具有 1024 字节内存的计算机受益于前向声明,因为它们可以一次编译 C,但是为什么,哦,为什么,我今天必须在同一个源文件中预先声明函数?我有千兆字节的内存可用?! @Gunchars 说得好; C++ 设法解析可能在其函数体内相互引用的内联成员函数。在这一点上,它只是历史惯性;没有一个实现可以在不被指责为无端不兼容的情况下进行更改,标准委员会对进行彻底的更改持谨慎态度是可以理解的。也许它仍然会发生;毕竟我们现在可以在函数开头声明变量了。【参考方案2】:

C 中函数的前向声明通常有两种不同的用途。

模块

导出函数的标头在客户端模块中包含的头文件中声明。

相互递归

在相互递归中,两个函数重复调用对方。如果没有前向声明,两个函数之一将在另一个函数的主体中未声明。

例子:

int Odd(int n);

int Even(int n)

    return (n == 0)? 1: Odd(n - 1);


int Odd(int n)

    return (n == 0)? 0: Even(n - 1);

虽然有了函数指针,我们可以不用前向声明:

int (*odd)(int n);

int Even(int n)

    return (n == 0)? 1: odd(n - 1);


int Odd(int n)

    return (n == 0)? 0: Even(n - 1);


void Init(void)

    odd = Odd;
    ...

【讨论】:

【参考方案3】:

您应该按照有意义的顺序声明函数。这应该在您遵循的编码风格文档中进行描述。常见设计的一个例子是:

包含所有公开可用函数声明的 h 文件。 顶部包含所有私有函数声明的 c 文件。 然后在同一个 c 文件中遵循公共函数的函数定义。 然后在该 c 文件的末尾,私有函数的函数定义。

除了样式和设计问题之外,如果在函数调用之前根本没有可见的原型,那么古老的 C 版本将开始“组成”函数参数和返回类型。

【讨论】:

【参考方案4】:

前向声明取决于程序的需要。程序员可以自己设计。

理解意义:在C和C++中,上面一行代表一个 函数的前向声明,是函数的原型。 处理此声明后,编译器将允许 程序代码在其余部分引用实体 printThisInteger 该程序。必须在某处提供函数的定义 (相同的文件或其他文件,这将是由 链接器正确匹配对特定函数的引用 或具有定义的几个目标文件,这些文件必须是唯一的,在 另一个):

【讨论】:

如果你要从***复制和粘贴一段,你至少可以提供一个链接到你抄袭的Forward declaration article。

以上是关于C编程中前向声明的意义是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 Objective-C 中前向声明枚举

为啥我不能使用双冒号在命名空间中前向声明一个类?

在另一个函数中前向声明“constexpr”函数——编译器错误?

C 编程:前向变量参数列表

术语:前向声明与函数原型

C ++中类定义中int&x声明的意义是啥[重复]