关于kr c:ANSI C和K&R C之间的主要区别是什么?

关于kr c:ANSI C和K&R C之间的主要区别是什么?

What are the major differences between ANSI C and K&R C?

ANSI C上的Wikipedia文章说:

One of the aims of the ANSI C standardization process was to produce a superset of K&R C (the first published standard), incorporating many of the unofficial features subsequently introduced. However, the standards committee also included several new features, such as function prototypes (borrowed from the C++ programming language), and a more capable preprocessor. The syntax for parameter declarations was also changed to reflect the C++ style.

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

编辑:我相信K&R书的封面上写着" ANSI C"。 至少我相信自己在家中拥有的版本。 那么也许没有区别了?


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

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


功能原型是K&R C和C89之间最明显的变化,但还有很多。标准化C库也进行了大量重要工作。即使标准C库是对现有实践的整理,它也对多种现有实践进行了整理,这使它变得更加困难。 P.J. Plauger的书《标准C库》是一本很好的参考书,还讲述了为什么该库以这种方式结束的幕后细节。

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

在大多数情况下,如果您不需要维护标准的C代码库,那么您不必担心就可以感到高兴。如果您这样做了-或更糟糕的是,如果您想将旧程序提高到更现代的标准-那么您会感到同情。


两者之间有一些细微的差异,但我认为K&R的更高版本适用于ANSI C,因此不再存在真正的差异。
由于缺少更好的术语," C Classic"的功能定义方式略有不同,即

1
2
3
4
5
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;
    }

    1
    2
    3
    4
    5
    int f(x)
    int x;
    {
        return x + 1;
    }

    都是一样的


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

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

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

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

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


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

    区别在于:

  • 原型
  • 广泛的角色支持和国际化
  • 支持const和volatile关键字
  • 允许将函数指针用作取消引用

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

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

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

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

  • 在二进制补码平台上,整数溢出自然会以静默方式自动换行,在结果介于INT_MAX + 1u和UINT_MAX之间的情况下,可以依靠包含小于" int"的无符号值的操作来表现该值好像是无符号的不能提升为更大的类型,也不用作>>的左操作数,也不用作/%的操作数或任何比较运算符。顺便说一句,该标准的基本原理将其作为小型无符号类型升级为带符号的原因之一。

  • 在C89之前,尚不清楚上述假设不能自然地成立的平台编译器无论多长都可以支持这些假设,但是毫无疑问,可以轻松,廉价地支持这些假设的平台编译器可以支持这些假设。应该这样做。 C89标准的作者不必费心地说出来,因为:

  • 如果编译器的作者不是故意使自己变钝,那么他们在实用时会继续这样做,而不必告诉他们(提倡使用小的无符号值签名)的理由强烈地强化了这种观点。

  • 该标准仅要求实现能够运行一个可能编写的程序而不会引起堆栈溢出,并且意识到虽然钝的实现可以将任何其他程序视为未定义行为,但并不认为值得为钝的编译器编写者担心"符合"但无用的实现。

  • 尽管" C89"被同时解释为"由C89定义的语言,以及平台提供的任何其他功能和保证",但是gcc的作者一直在推动一种解释,该解释排除了任何功能和保证,但其范围超出了C89要求的范围。


    我认为最大的不同是函数原型和描述函数参数类型的语法。


    尽管竞争激烈,但K&R过去并且现在仍然能够提供从低层到硬件上层的任何东西。
    现在的问题是找到一个编译器(最好是免费的),该编译器可以在几百万行K&R C上进行干净的编译而又不必弄乱它,并且可以在AMD多核处理器等设备上运行。

    据我所知,在查看了GCC 4.xx系列的源代码之后,没有简单的技巧可以将-traditional和-cpp-traditional滞后功能重新激活到它们先前的工作状态,而不会花费太多精力 并且更容易从头开始构建K&R pre-ansi编译器。


    推荐阅读