ANSI C和K&R C之间的主要区别是什么?

维基百科关于ANSI C的文章说:

ANSI C标准化过程的目的之一是生成K&R C(第一个公布的标准)的超集,其中包含许多后来引入的非官方特征。 然而,标准委员会还包括了一些新的特性,比如函数原型(借用C ++编程语言)和更强大的预处理器。 参数声明的语法也被改变,以反映C ++风格。

这让我觉得有分歧。 但是,我没有看到K&R C和ANSI C之间的比较。有没有这样的文件? 如果不是,主要区别是什么?

编辑:我相信K&R书在封面上说“ANSI C”。 至less我相信我在家有这个版本。 所以也许这没有什么区别了?

这里可能有一些关于“K&R C”是什么的混淆。 该术语是指第一版“The C Programming Language”中记载的语言。 粗略地说,大约在1978年贝尔实验室C编译器的input语言。

Kernighan和Ritchie参与了ANSI标准化过程。 “ANSI C”方言取代“K&R C”,“C语言程序devise语言”后续版本采用ANSI惯例。 “K&R C”是一种“死语言”,除非某些编译器仍然接受遗留代码。

function原型是K&R C和C89之间最明显的变化,但还有很多其他变化。 很多重要的工作也进入了C库的标准化。 尽pipe标准的C语言库是对现有惯例的编纂,但它编纂了多种现有的惯例,这使得它更加困难。 PJ Plauger的书“标准C图书馆 ”是一本非常好的参考书,同时也讲述了图书馆为什么要这样做的幕后细节。

ANSI / ISO标准C在很多方面与K&R C非常相似。 目的是大多数现有的C代码应该build立在ANSI编译器上,没有太多的改变。 但是,至关重要的是,在准标准时代,语言的语义可以由每个编译器厂商来解释。 ANSI C引入了语言语义的一个通用描述,使所有的编译器处于平等的地位。 20年后的今天很容易理所当然,但这是一个重大的成就。

大多数情况下,如果你没有一个标准的C代码库来维护,你应该很高兴你不必担心它。 如果你这样做 – 或者更糟的是,如果你想把一个旧的程序带到更现代化的标准 – 那么你就有我的同情心。

有一些细微的差别,但是我认为K&R的后期版本是ANSI C的,所以再也没有真正的区别了。
由于缺乏更好的条款,“C Classic”的定义函数的方式略有不同,

int f( p, q, r ) int p, float q, double r; { // Code goes here } 

我相信其他的区别是函数原型。 原型不必 – 实际上他们不能 – 拿一个参数或types的列表。 在ANSI C他们这样做。

  1. 函数原型。
  2. 常量和易失性限定符。
  3. 广泛的性格支持和国际化。
  4. 允许使用函数指针而不需要解引用。

另一个区别是函数返回types和参数types不需要定义。 他们将被认为是整数。

 f(x) { return x + 1; } 

 int f(x) int x; { return x + 1; } 

是相同的。

  • 函数原型:ANSI C采用c ++函数原型技术,其中函数定义和声明包括函数名称,参数t,数据types和返回值数据types。函数原型使ANSI c编译器能够在用户程序中检查函数调用,通过无效的参数个数或不兼容的参数数据types。这些解决了K&R C编译器的一个主要弱点:用户程序中的无效调用通常会通过编译,但会导致程序在执行时崩溃

区别在于:

  1. 原型
  2. 广泛的性格支持和国际化
  3. 支持const和volatile关键字
  4. 允许函数指针用作解引用

ANSI C和K&R C的主要区别如下:

  • function原型
  • 支持const和volatile数据types限定符
  • 支持广泛的人物和国际化
  • 允许使用函数指针而不需要解引用

ANSI C采用c ++函数原型技术,其中函数定义和声明包括函数名称,参数的数据types和返回值数据types。 函数原型使ANSI C编译器能够在用户程序中检查传递无效参数或不兼容参数数据types的函数调用。 这些修复了K&R C编译器的主要弱点。

例如:声明一个函数foo,并要求foo带两个参数

  unsigned long foo (char* fmt, double data) { /*body of foo */ } 

我认为最大的区别是函数原型和用于描述函数参数types的语法。

还没有人提到的一个主要的区别是,在ANSI之前,C主要由先例而不是规范来定义; 在某些操作会对某些平台产生可预测的后果的情况下(例如,在两个不相关的指针上使用关系操作符),先例强烈希望程序员可以使用平台保证。 例如:

  1. 在所有指向所有对象的指针中定义自然排名的平台上,可以依靠关系运算符应用于任意指针来产生该排名。

  2. 在testing一个指针是否“大于”另一个指针的自然方法的平台上,除了产生一个真或假的值之外,从来没有任何副作用,关系运算符对任意指针的应用同样可以依赖于永远不会有任何一方 – 除了产生真实或错误的价值之外的其他影响。

  3. 在两个或多个整数types共享相同大小和表示的平台上,可以使用指向任何这种整数types的指针来读取或写入具有相同表示的任何其他types的信息。

  4. 在二进制补码平台中,整数溢出自然地自然地包装,当结果在INT_MAX + 1u和UINT_MAX之间时,可以依赖包含小于“int”的无符号值的操作,就好像该值是无符号的没有被提升到更大的types,也没有被用作>>的左操作数,也没有被用作/%或者任何比较运算符的操作数。 顺便说一句,标准的理由给出了这个小无符号types促进签名的原因之一

在C89之前,尚不清楚上述假设不会自然持有的平台的编译程度到底能维持这些假设的程度,但毫无疑问,平台的编译人员可以轻而易举地维护这些假设应该这样做。 C89标准的作者没有打算明确地说,因为:

  1. 作家不是故意钝的编纂者会在不需要被告知的情况下继续做这样的事情(为促进签署小的无符号价值而提供的理论基础强烈地强调了这一观点)。

  2. 该标准只要求实现能够运行一个没有堆栈溢出的可能devise的程序,并且认识到虽然一个顽固的实现可以将任何其他程序视为调用未定义的行为,但并不认为值得担心编译器写作者实现“符合”,但没用。

虽然“C89”同时被解释为“C89所定义的语言,加上任何附加function并保证平台提供”,但是海湾合作委员会的作者一直在推动一种排除C89规定的特性和保证的解释。

尽pipeK&R的所有权利都是自由的,并且相当有能力提供从低到接近硬件的各种东西。 现在的问题是find一个编译器(最好是免费的),可以在数千万行K&R C上进行干净的编译,而不必乱搞。并运行在AMD多核处理器上。

就我所见,看过GCC 4.xx系列的源代码,没有简单的黑客来重新激活传统的和传统的滞后function到他们以前的工作状态,没有比我预先准备好的更多的function放入。更简单的从零开始构build一个K&R预编译器。