提问者:小点点

为什么在C中编写声明和使用函数的顺序与C相反并不重要


我想知道,当我用C#Unity为我的游戏编写代码时,我可以在使用它们之后声明代码中的无效,并且代码仍然有效。另一方面,当我编写纯C代码时,我需要在使用它们之前声明我的函数,我很好奇为什么会出现这种差异?


共1个答案

匿名用户

我想知道,当我用C#Unity为我的游戏编写代码时,我可以在使用它们之后声明代码中的无效,并且代码仍然有效。另一方面,当我编写纯C代码时,我需要在使用它们之前声明我的函数,我很好奇为什么会出现这种差异?

简短答复:

  • 因为C和C#是完全不同的编程语言,它们有完全独立的背景和编译器。
  • 因为C是在C之上构建的,并且继承了它的编译过程。
  • ... C是在编译器只通过源代码1次,最小的内存使用,这就需要前向声明的时候设计的,而C#是在编译器可以进行“多遍”运行和构建大型内存程序模型的时候设计的这就消除了预先声明的必要性。

详细回答:

请注意,我所说的“多次传递”并不是指编译器实际上从头开始多次重新解析和处理源文件;这意味着,在C#编译器解析源代码(只发生一次)后,它可以提取出程序实际使用的东西(如类型、方法等)的所有符号,并将其存储在内存中的列表中(已用东西列表)只有在建立了程序完全定义的所有内容的列表(list of defined things)并比较了这两个列表后,才会抱怨缺少/损坏的引用。而在20世纪70年代和80年代早期,计算机根本没有足够的内存来存储这些列表,因此C需要它。

现在,在2021年的今天,可以说有可能有一个不需要前向声明的C(甚至是C编译器),但是这是另一个与太多原因有关的话题,我不会深入讨论(尽管主要原因可能是因为根本没有任何需求:所有现有的C和C程序都已经有了前向声明,没有人会仅仅因为一个编译器支持它而编写没有前向声明的C或C程序。国际标准化组织C和C语言设计委员会可以引入它,但是因为前向声明是C语言设计的基础,它将是对更广泛的C和C生态系统的真正巨大的突破性变化,每个人都会抱怨。

C是在C之上构建的,因此它继承了向前声明的要求。与当时的其他OOP语言(如Smalltalk和Object Pascal)相比,C与C源代码的兼容性是C受欢迎的一个巨大的积极因素,后者要求现有的C程序要么完全移植到一种新语言,要么要求C程序以二进制形式链接,这使一切变得复杂。

Objective-C是另一种构建在C之上的OOP语言,它也继承了C对前向声明的要求

可以说,C本来可以设计成无需前向声明就可以编译,但这会增加大量复杂性w.r.t.它与C源文件的兼容性,而且几乎可以肯定的是,推迟C本身的发布日期,因为敲定C兼容编译而无需提前声明的具体工作规范需要几个月甚至几年才能完成。

回顾上世纪90年代中期的Java(最终是C#),这些现代编程语言根本不打算与C程序在源代码上兼容(尽管使用了共享的花括号语法),这意味着这些语言不需要围绕当时硬件限制所施加的限制进行设计。

这并不是说Java语言的人机工程学设计没有受到编译器设计的影响:Java仍然需要每个文件1个类型和CLASSPATH/SOURCEPATH胡说八道。我知道这些限制对于Java当时非常快速和简单的编译器来说是必要的,这确实意味着所有Java项目都将有一个可预测的布局,但25年后,这些限制越来越被视为给程序员带来了一个非常乏味的负担,并且总体上是愚蠢的限制,没有什么好处。然而,与C#、Rust、Kotlin、Go、Swift等后Java语言相比,后者将项目的源代码安排与编译输出完全解耦

我想你已经读过了:C语言中的转发声明是什么如果你没有读过,那么你应该先读一读。

现在,考虑这张表并找出相关性: