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

时间:2008-08-22 14:29:27

标签: c kr-c c89

Wikipedia article on ANSI C说:

  

ANSI C标准化过程的目标之一是制作K& R C(第一个发布的标准)的超集,其中包含随后引入的许多非官方特征。但是,标准委员会还包括一些新功能,例如函数原型(借用C ++编程语言)和更强大的预处理器。参数声明的语法也被更改以反映C ++样式。

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

编辑:我相信K& R书的封面上写着“ANSI C”。至少我相信我在家里的版本确实如此。那么也许就没有区别了?

11 个答案:

答案 0 :(得分:29)

这里可能存在一些关于“K& R C”是什么的混淆。该术语指的是第一版“C程序设计语言”中记录的语言。粗略地说:贝尔实验室C编译器的输入语言大约是1978年。

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

答案 1 :(得分:16)

功能原型是K& R C和C89之间最明显的变化,但还有很多其他原因。许多重要的工作也用于标准化C库。尽管标准C库是现有实践的编纂,但它编纂了多个现有实践,这使其更加困难。 P.J. Plauger的书The Standard C Library,是一本很好的参考书,并且还讲述了为什么这个库以它的方式结束的幕后细节。

ANSI / ISO标准C在很多方面与K& R C非常相似。它的目的是大多数现有的C代码应该在ANSI编译器上构建而不需要很多更改。然而,至关重要的是,在预标准时代,语言的语义可供每个编译器供应商解释。 ANSI C引入了语言语义的通用描述,使所有编译器处于平等的地位。现在很容易将此视为理所当然,大约20年后,但这是一项重大成就。

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

答案 2 :(得分:12)

存在一些细微差别,但我认为K& R的后续版本适用于ANSI C,因此不再存在真正的差异。
由于缺乏更好的术语,“C Classic”的定义函数的方式略有不同,即

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

我认为另一个区别是功能原型。原型不必 - 实际上他们不能 - 采取一系列参数或类型。在ANSI C中他们这样做。

答案 3 :(得分:6)

  1. 功能原型。
  2. 常数&挥发性资格。
  3. 广泛的人格支持和国际化。
  4. 允许在不解除引用的情况下使用函数指针。

答案 4 :(得分:3)

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

f(x)
{
    return x + 1;
}

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

是完全相同的。

答案 5 :(得分:2)

区别在于:

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

答案 6 :(得分:2)

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

答案 7 :(得分:2)

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

  • 功能原型设计
  • 支持const和volatile数据类型限定符
  • 支持广泛的角色和国际化
  • 允许在不解除引用的情况下使用的函数指针

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

示例:声明一个函数foo并要求foo接受两个参数

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

答案 8 :(得分:1)

我认为最大的单一差异是函数原型和用于描述函数参数类型的语法。

答案 9 :(得分:1)

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

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

  2. 在测试一个指针是否大于"的自然方法的平台上。除了产生真值或假值之外,另一个没有任何副作用,关系运算符应用于任意指针同样可以依赖于除了产生真或假值之外不会产生任何副作用。

    < / LI>
  3. 在两个或多个整数类型共享相同大小和表示的平台上,可以依赖指向任何此类整数类型的指针来读取或写入具有相同表示形式的任何其他类型的信息。

  4. 在两个补码平台上,整数溢出自然地无声地换行,一个涉及小于&#34; int&#34;的无符号值的操作。如果结果在INT_MAX + 1u和UINT_MAX之间并且它没有被提升为更大的类型,也没有被用作>>的左操作数,也没有任何一个可以依赖于表示无符号值的行为/%或任何比较运算符的操作数。 顺便提一下,标准的基本原理是将小型无符号类型提升为签名的原因之一。

  5. 在C89之前,尚不清楚上述假设不会自然持有的平台编译器的长度,无论如何都可能会维持这些假设,但毫无疑问,平台的编译器很容易并且廉价地坚持这样的假设应该这样做。 C89标准的作者没有明确说出因为:

    1. 编写者并不是故意使用的编译器会在实际操作时继续做这些事情,而不必被告知(促使签署小的无符号值的理由强烈强调了这一观点)。

    2. 标准只要求实现能够在没有堆栈溢出的情况下运行一个可能设计的程序,并且认识到虽然一个钝的实现可以将任何其他程序视为调用未定义的行为但是没有认为它值得担心的是,编译器编写者编写的实现符合&#34;符合&#34;但没用。

    3. 虽然&#34; C89&#34;被同义解释为C89定义的语言,加上平台提供的任何其他功能和保证,gcc的作者一直在推行一种解释,排除了C89规定的任何特征和保证。< / p>

答案 10 :(得分:-1)

尽管对K&amp; R的所有声明都是并且能够提供从低位接近硬件的任何类型的东西。 现在的问题是找到一个编译器(最好是免费的),可以在几百万行K&amp; R C上进行干净的编译,而不必麻烦它。并在像AMD多核处理器这样的东西上运行。

据我所知,看过GCC 4.xx系列的来源,没有简单的黑客重新激活-traditional和-cpp-traditional延迟功能到他们之前的工作状态,而没有比我更多的效果我很喜欢投入。并且更容易从头开始构建K&amp; R pre-ansi编译器。