但是C是一种底层语言


自C语言问世以来的过去十年中,已经创建了许多有趣的编程语言。 其中一些仍在使用,其他一些影响了下一代语言,第三种语言的流行已悄然消失。 同时,陈旧的,有争议的,原始的,以其C语言(及其继承人)这一代最糟糕的传统制成,比所有生物都活泼。


批评C是我们行业的经典书信流派。 听起来更大,然后更安静,但是最近它确实很棒。 一个例子是大卫·西斯韦尔(David Ciswell )不久前在我们的博客上发表的文章“ C不是低级语言”的译文。 您可以对C说不同的话,在语言的设计中确实存在许多令人不愉快的错误,但是在“低级”拒绝C太多了!


为了不容忍这种不公正,我鼓起勇气,试图决定什么是低级编程语言以及他们希望从中获得什么实践,然后我回顾了批评家C的观点。这就是本文的结果。


目录内容



批评论点C


以下是C语言批评家的一些论点,包括David Chiznell在一篇文章中列出的论点:


  1. 抽象的C语言机器与过时的PDP-11体系结构太相似了,后者早已停止与流行的现代处理器设备相对应。
  2. 抽象机器和真实机器的设备之间的不匹配使优化语言编译器的开发变得复杂。
  3. 语言标准的不完整和复杂性导致标准实施中的差异。
  4. C语言的主导地位不允许探索替代的处理器体系结构。

首先,确定低级语言的要求,然后返回给定的参数。


低级编程语言


没有通用的低级语言定义。 但是,在讨论有争议的问题之前,最好至少对争端有一些初步要求。


没有人会说汇编语言是最底层的。 但是在每个平台上它都是唯一的,因此这种语言的代码无法移植。 即使在向后兼容的平台上,您可能也需要使用一些新的说明。


从这里开始,是对低级语言的首要要求:它应保留流行平台的通用功能 。 简而言之,编译器必须是可移植的。 编译器的可移植性简化了用于新平台的语言编译器的开发,并且编译器支持的多种平台消除了开发人员为每台新机器重写应用程序的需要。


第一个要求与特殊程序开发人员的愿望相冲突:编程语言,驱动程序,操作系统和高性能数据库。 编写这些程序的程序员希望能够手动优化,直接使用内存等。 总之,低级语言应允许使用平台实现的细节


在这两个需求之间找到平衡-确定平台共有的方面并访问尽可能多的详细信息-这是开发低级语言困难的根本原因。


请注意,对于这种语言而言,高级抽象并不是那么重要-使其成为平台,编译器和开发人员之间的契约更为重要。 并且如果有合同,那么就需要一种独立于特定实施标准语言


我们的第一个要求-目标平台共有的功能-是用抽象语言机器表达的,因此我们将以C开始讨论。


不只是关于PDP-11


C语言出现的平台是PDP-11。 它基于传统的冯·诺依曼体系结构 ,在该体系结构中,程序由中央处理器顺序执行,并且存储器是扁平磁带,其中存储了数据和程序。 这种体系结构很容易在硬件中实现,并且随着时间的流逝,所有通用计算机都开始使用它。


对冯·诺依曼架构的现代改进旨在消除其主要瓶颈-延迟处理器与内存之间的数据交换(英语为冯·诺依曼瓶颈 )。 内存和CPU性能的差异导致出现了处理器的缓存子系统(单级和后来的多级)。


但是这些天甚至缓存都不够。 现代处理器已经成为超标量。 指令的异常执行( 指令级并行性 )以及分支预测器会部分补偿指令从内存接收数据时的延迟。


顺序抽象机C(以及许多其他语言)并没有特别模仿PDP-11的工作,而是模仿了根据von Neumann架构原理布置的任何计算机的工作。 它包含围绕具有单核处理器的体系结构:台式机和服务器x86,移动ARM,它们来自Sun / Oracle SPARC和IBM POWER。


随着时间的流逝,几个处理内核开始集成到一个处理器中,结果有必要保持每个内核的缓存和所需的核间交互协议的一致性。 冯·诺依曼体系结构因此扩展到了几个核心。


抽象机C的原始版本是顺序的,不反映通过内存交互的程序执行线程的存在。 标准中内存模型的出现将抽象机的功能扩展到了并行。


因此,断言抽象C机器长期以来与现代处理器的结构不一致,这与特定语言无关,而只是使用von Neumann架构的计算机,包括并行执行。


但是,作为一名从业人员,我想指出以下几点:我们可以假设Fonneimann方法已经过时,可以假设它是相关的,但这并不能消除当今通用架构使用传统方法派生的事实。


冯·诺伊曼(von Neumann)架构的标准化和便携式实施例-抽象的C机-在所有主要平台上均可方便地实现,因此,作为便携式汇编器,它应有的受欢迎程度。


优化编译器和低级语言


我们对低级语言的第二个要求是访问每个流行平台的低级实现细节。 对于C而言,这是直接以字节数组形式处理内存和对象,并具有直接使用字节地址和高级指针算法的能力。


C批评家指出,语言标准为例如结构和关联中各个字段的位置提供了太多保证。 再加上指针和循环的原始机制,这会使优化器的工作复杂化。


确实,更具声明性的方法将允许编译器独立解决内存中的数据对齐或结构中字段的最佳顺序的问题。 更高级别的循环可提供矢量化时所需的自由度。


在这种情况下,C开发人员的位置如下:低级语言应允许它以足够低的水平工作,以使程序员能够独立解决优化问题。 在C中,可以用作编译器,例如选择SIMD指令并将数据正确地放入内存中。


换句话说,正是由于存在底层工具,我们访问每个平台的实现细节的需求才与开发人员优化编译器的愿望相冲突。


有趣的是,Lifewell在其题为“ C不是低级语言”的文章中自相矛盾地认为C 太低级,表明其中缺少高级工具。 但是从业人员只需要底层工具,否则该语言将无法用于开发操作系统和其他底层程序,也就是说,它将无法满足我们的第二个要求。


从描述优化问题(即C)的角度出发,我想指出的是,与GCC或Clang相比,目前在优化高级语言(相同的C#和Java)的编译器上投入了不少精力。 函数式语言还具有足够有效的编译器:MLTon,OCaml等。 但是同一个OCaml的开发人员仍然可以以C代码的一半速度拥有最高的性能...


标准绝对好


Chiznell在他的文章中引用了2015年进行的一项调查的结果:许多程序员在解决理解C标准的问题时犯了错误。


我想其中一位读者正在使用C标准,我的纸质版本为C99,广告页为900页,这不是简明的方案规范,页数少于100页,也不是标准的ML,包含300页。没有人获得C标准:既没有编译器开发人员,也没有文档开发人员,也没有程序员。


但是我们必须理解,C标准是在许多“几乎几乎不存在”的兼容方言出现之后才发展起来的。 ANSI C的作者在总结现有实现方面做得很出色,并在语言设计中涵盖了无数不正交的“拐杖”。


有人承诺实施这样的文档似乎很奇怪。 但是C已经被许多编译器实现。 我不会重述其他人关于80年代后期UNIX世界动物园的故事,尤其是因为那时我本人并不十分自信,直到五岁为止。 但是,显然,行业中的每个人都确实需要一个标准。


伟大的事情是它存在并且至少由三个大型编译器和许多较小的编译器实现,它们一起支持数百个平台。 声称低级语言之王的竞争者语言C都无法拥有如此多样性和多功能性。


实际上,当前的C标准还不错。 或多或少有经验的程序员能够在合理的时间内开发出非优化的C编译器,这被许多半业余实现(相同的TCC,LCC和8cc)所证实。


拥有公认的标准意味着C满足了我们对低级语言的最后要求:该语言基于规范而非特定的实现。


替代架构-特殊计算


但是Lifewell引用了另一个论点,回到实现von Neumann架构选项的现代通用处理器的设备。 他声称改变中央处理器的原理是有意义的。 再一次,这种批评不是特定于C,而是特定于命令式编程的最基本模型。


确实,对于传统方法而言,可以通过顺序执行程序来替代许多方法:GPU风格的SIMD模型,抽象Erlang机器风格的模型等。 但是,在中央处理器中使用这些方法时,每种方法的适用性均受到限制。


例如,GPU在游戏和机器学习中显着地增加了矩阵,但是它们很难用于光线跟踪。 换句话说,此模型适用于专用加速器,但不适用于通用处理器。


Erlang在群集中工作得很好,但是很难执行高效的快速排序或快速哈希表。 独立角色模型最好在较大的集群中较高级别上使用,在该集群中,每个节点仍然是与传统处理器相同的高性能计算机。


同时,现代的x86兼容处理器在目的和操作原理上早就包含了类似于GPU的矢量指令集,但总体上保留了von Neumann风格的通用处理器电路。 我毫不怀疑,任何流行的处理器都将包含任何相当通用的计算方法。


有这样的权威意见:未来在于专用的可编程加速器。 在这种非同寻常的条件下,开发具有特殊语义的语言确实很有意义。 但是,通用计算机曾经并且仍然与PDP-11非常相似,对于此类计算机,C语言的命令式语言非常适合。


C会活


Chiznell的文章存在一个基本矛盾。 他写道,为确保C程序的速度,处理器模仿抽象的C机器(以及人们早已忘记的PDP-11),之后指出了这种机器的局限性。 但是我不明白为什么这意味着“ C不是低级语言”。


通常,这不是关于C语言的缺陷,而是对常见的冯·诺依曼风格的体系结构以及由此产生的编程模型的批评。 但是到目前为止,业界似乎还没有准备好放弃熟悉的体系结构(至少不是在通用处理器中)。


尽管可以使用诸如GPU和TPU之类的许多专用处理器,但冯·诺依曼(von Neumann)架构目前处于控制之中,行业需要一种语言,使其能够在最流行的架构的框架内尽可能低地工作。 C(及其直接家族)非常简单,可移植到数十种平台和标准化编程语言中。


尽管如此,C还是有不足之处:一个过时的函数库,一个复杂而又不一致的标准以及严重的设计错误。 但是,很明显,该语言的创建者仍然做对了一些事情。


无论如何,我们仍然需要一种低级语言,它是专门为流行的Fonneimann计算机构建的。 并且让C过时,但是显然,它的任何后继者仍必须建立在相同的原则上。

Source: https://habr.com/ru/post/zh-CN465429/


All Articles