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

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

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

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

有帮助吗?

解决方案

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

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

其他提示

功能原型是 K&R C 和 C89 之间最明显的变化,但还有很多其他变化。C 库的标准化也投入了大量的重要工作。尽管标准 C 库是现有实践的编纂,但它编纂了 多种的 现有的做法,这使得它变得更加困难。P.J.普劳格的书, 标准 C 库, ,很有参考价值,还讲述了一些幕后细节 为什么 图书馆就这样结束了。

ANSI/ISO 标准 C 在大多数方面与 K&R C 非常相似。大多数现有的 C 代码应该构建在 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  
}

我相信另一个区别是函数原型。原型不必(事实上他们不能)采用参数或类型列表。在 ANSI C 中是这样的。

  1. 函数原型。
  2. 常量和易变限定符。
  3. 广泛的字符支持和国际化。
  4. 允许在不取消引用的情况下使用函数指针。

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

f(x)
{
    return x + 1;
}

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

是相同的。

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

区别在于:

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

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 */
 }

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

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

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

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

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

  4. 在整数溢出自然自动换行的补码平台上,如果结果介于 INT_MAX+1u 和 UINT_MAX 之间,则涉及小于“int”的无符号值的操作可能会表现为该值无符号。没有提升为更大的类型,也没有用作左操作数 >>, ,也不是任一操作数 /, %, ,或任何比较运算符。 顺便说一句,该标准的基本原理将此作为小型无符号类型升级为有符号类型的原因之一.

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

  1. 编写者不是故意迟钝的编译器会在实际情况下继续做这样的事情,而不必被告知(将小的无符号值提升为有符号的理由强烈强化了这一观点)。

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

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

尽管有所有相反的说法,K&R 过去和现在都非常有能力提供从底层到硬件的任何类型的东西。现在的问题是找到一个编译器(最好是免费的),它可以对几百万行 K&R C 进行干净的编译,而不必搞乱它。并且可以在 AMD 多核处理器之类的东西上运行。

据我所知,在查看了 GCC 4.x.x 系列的源代码后,没有简单的方法可以将 -traditional 和 -cpp-traditional 滞后功能重新激活到之前的工作状态,而无需付出比我准备更多的努力普京。从头开始构建 K&R pre-ansi 编译器也更简单。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top