46

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

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

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

编辑:我相信 K&R 书的封面上写着“ANSI C”。至少我相信我家里的版本是这样的。所以也许不再有区别了?

4

11 回答 11

32

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

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

于 2008-08-22T14:48:18.003 回答
18

函数原型是 K&R C 和 C89 之间最明显的变化,但还有很多其他变化。许多重要的工作也涉及标准化 C 库。尽管标准 C 库是对现有实践的编纂,但它编纂了多种现有实践,这使其变得更加困难。PJ Plauger 的书The Standard C Library是一本很好的参考书,它还讲述了为什么图书馆会以这种方式结束的一些幕后细节。

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

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

于 2008-08-28T03:15:27.200 回答
12

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

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

我相信另一个区别是函数原型。原型不必——事实上他们不能——获取参数或类型的列表。在 ANSI C 中,他们这样做了。

于 2008-08-22T14:35:12.060 回答
8
  1. 函数原型。
  2. constant 和 volatile 限定符。
  3. 广泛的字符支持和国际化。
  4. 允许在不取消引用的情况下使用函数指针。
于 2011-02-28T14:28:38.480 回答
3

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

f(x)
{
    return x + 1;
}

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

是相同的。

于 2008-09-11T01:23:11.220 回答
3

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

  • 功能原型
  • 支持 const 和 volatile 数据类型限定符
  • 支持宽字符和国际化
  • 允许在不取消引用的情况下使用函数指针

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

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

 unsigned long foo (char* fmt, double data)
 {
      /*body of foo */
 }
于 2013-02-28T01:40:22.527 回答
2

区别在于:

  1. 原型
  2. 广泛的字符支持和国际化
  3. 支持 const 和 volatile 关键字
  4. 允许函数指针用作解引用
于 2009-02-23T04:38:25.463 回答
2
  • 函数原型:ANSI C 采用 c++ 函数原型技术,其中函数定义和声明包括函数名称、参数 t、数据类型和返回值数据类型。函数原型使 ANSI c 编译器能够检查用户程序中传递无效参数数量的函数调用或不兼容的参数数据类型。这些修复了 K&R C 编译器的一个主要弱点:用户程序中的无效调用通常会通过编译,但会导致程序在执行时崩溃
于 2011-06-04T15:46:19.137 回答
2

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

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

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

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

  4. 在整数溢出自然无声包装的二进制补码平台上,在结果介于 INT_MAX+1u 和 UINT_MAX 之间的情况下,可以依赖涉及小于“int”的无符号值的操作表现得好像该值是无符号的没有提升为更大的类型,也没有用作 的左操作数,也没有用作 , 的操作数>>或任何比较运算符。 顺便说一句,标准的基本原理将此作为小型 unsigned 类型提升为 signed 的原因之一/%

在 C89 之前,不清楚上述假设不会自然成立的平台的编译器会在多大程度上支持这些假设,但毫无疑问,平台的编译器可以轻松且廉价地支持这些假设应该这样做。C89 标准的作者没有费心明确表示,因为:

  1. 编写者不是故意迟钝的编译器会在实际可行时继续做这些事情而不必被告知(将小的无符号值提升为有符号的理由强烈地加强了这种观点)。

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

尽管“C89”同时被解释为“C89 定义的语言,以及平台提供的任何附加功能和保证”,但 gcc 的作者一直在推动一种排除 C89 规定之外的任何功能和保证的解释。

于 2016-07-05T22:58:48.190 回答
1

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

于 2008-08-22T14:31:19.120 回答
-1

尽管所有对 contary K&R 的声称过去并且完全能够提供从低到接近硬件的任何类型的东西。现在的问题是找到一个编译器(最好是免费的),它可以在几百万行 K&R C 上进行干净的编译,而不必弄乱它。并且可以在 AMD 多核处理器之类的东西上运行。

据我所见,在查看了 GCC 4.xx 系列的源代码后,没有任何简单的技巧可以将 -traditional 和 -cpp-traditional 滞后功能重新激活到它们以前的工作状态,而无需比我准备的更多的努力放入。从头开始构建 K&R pre-ansi 编译器更简单。

于 2017-01-05T21:47:58.177 回答