【问题标题】:Why earlier versions of C made it mandatory to declare variables in the beginning? [duplicate]为什么早期版本的 C 强制在开始时声明变量? [复制]
【发布时间】:2015-03-27 03:17:19
【问题描述】:

我回顾了一些 C 的历史,我发现在 C 的早期版本中,就像在 C89 标准中一样,在块的开头声明变量是强制性的。

但我也发现 C99 标准规范有一些放宽,其中变量可以在使用之前在任何地方声明。

我的问题是为什么早期版本强制要求它?我的重点是了解当时在设计编译器时是否存在任何技术困难,从而阻止他们在任何时候识别声明。

另外,从编译器设计的角度来看,我理解,由于 C89 中存在这样的限制,在中间文件的帮助下处理变量声明和使用来存储映射是很容易的。但是有没有方法可以在不使用中间文件(比如一些基于内存的存储)的情况下处理这种情况?

【问题讨论】:

  • 不需要中间文件来存储映射,而且从来没有。
  • @AmrithKrishna 你基本上是在问编译器如何使用数组......?
  • 关闭投票者,请在投票前三思而后行,将其作为“主要基于意见”来关闭。 OP 要求对 C89 标准的一部分进行技术论证。
  • @FpggyDay:你错了,这太棒了(将数据和代码的范围最小化到它实际有用的地方——并且可以分配有意义的值——是可维护编程的基本原则),并且通过将问题的技术方面转移到意见陈述中,您正在增加这个问题应该作为基于意见来结束的印象。
  • 别忘了,早在 1970 年代初,当 C 语言刚被设计出来时,机器不一定有 64 KiB 的内存(它们有 less !)在其中工作。为了让编译器执行,简化是必要的。

标签: c++ c compiler-construction


【解决方案1】:

如果编译器预先看到所有局部/自动变量的综合列表,它可以立即计算出移动堆栈指针以为其保留堆栈内存的总量 - 只需对堆栈指针进行一次操作。如果它处理函数中遇到的 dribs 和 drabs 中的变量,增量地移动堆栈指针,那么最终会有更多的操作码专用于堆栈设置和堆栈指针更新。重要的是,无论何时执行进一步的函数调用,堆栈指针都是最新的。较新的编译器会做一些额外的工作来修补在考虑所有函数后移动堆栈指针的量。 (我敢说,这种努力是如此之少,以至于早期的标准更多地是由预先知道要做什么的概念吸引力来塑造的,而不是更加灵活的努力,但如果你只是想让某些东西发挥作用 - 为什么要付出额外的努力?)

【讨论】:

  • 这样的推论方式是,在计算机编译 C89 及之前的史前史中,用户需要花费大量时间来预解析每个块以找到所有本地人,然后再返回开始编译和发出代码,编译器是否应该以这样的一次性方式构建。
  • 由于新变量仍然可以在内部块中声明,您是否不需要回补丁(或忍受在函数中多次递增堆栈指针的低效率)?
  • @sepp2k 如果内部块在进入时分配堆栈内存并在退出时释放它,这并不奇怪。
  • @immibis goto 怎么样?
  • @ratchetfreak:你不能禁止 goto 进入一个有自己声明的变量的块,C89 允许它。 C 编译器必须通过考虑源和目标的“景观”来处理 goto,包括堆栈位置以及可能哪些变量在哪些寄存器中,并在跳转之前(或不太可能,就在之后)进行所需的任何调整。所以if (something) goto X; 不一定最终成为针对 X 的条件分支操作码,即使 CPU 有一个。
【解决方案2】:

C99 Rationale 没有直接解释为什么它在 C89 中不被允许,但确实说它是在 C99 中添加的,因为它在其他语言中被允许并且发现它很有用。

Rationale for International Standard — Programming Languages — C

§6.2.4 对象的存储期限

C99 的一个新特性:C89 要求块中的所有声明都出现在任何语句之前。另一方面,许多类似于 C 的语言(例如 Algol 68 和 C++)允许以任意方式混合声明和语句。发现此功能很有用并已添加到 C99。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-12
    • 2021-12-16
    • 2021-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多