HelloKitty • 2022-10-18 10:44
2625
本文由 51CTO技术栈 ,作者Serdar Yegulalp 撰写/授权提供,转载请注明原出处。
作者 | Serdar Yegulalp
译者 | 布加迪
策划 | 云昭
数十年来 C 语言一直可谓是编程界的扛把子。Linux、Windows、Mac 和许多其他操作系统的内核都能看到它的身影。C 语言几乎可以写任何程序,在编程语言中的地位,德高望重。它甚至可能是有史以来最具影响力的语言。它的语法启发了许多其他语言,包括 Cpp、Csharp、Java、JavaScript、Go、Perl 等等。
自 1972 年以来,C 编程语言一直是构建软件的主力语言之一。但是过去 50 年以来,已经涌现出数十种新语言,这些后辈语言的表现又如何?其中一些正在挑战C的统治地位,而另一些正在不断蚕食其地位。
撼山易,撼 C 语言难!在性能、裸机兼容性和普及性方面几乎没有语言能够击败 C。不过仍有必要看看 C 与一些主流语言相比表现如何。本文介绍了它与 C++、Java、C#、Go、Python 及最新的语言 Carbon 的详细对比。
C与C++
C 经常与 C++ 相比较;顾名思义,C++ 是作为 C 的扩展而创建的。C++和 C 之间的差异很大,甚至可以说差异过大。
虽然 C++ 在语法和方法上仍然酷似 C,但提供了许多有用的功能,这些功能是 C 本身并不直接随带的:命名空间、模板、异常和自动内存管理等。一般,需要顶级性能的项目(比如数据库和机器学习系统)通常用 C++ 编写,利用这些功能最大限度地发挥系统的性能。
此外,C++ 的步子比 C 迈得更大。即将发布的 C++ 23 带来了更多的功能,包括模块、协程和模块化标准库,以加快编译和更多的代码。相比之下,C 标准的下一个计划版本 C2x 却没增加多少功能,而是专注于保持向后兼容性。
问题在于,C++ 中的所有优点也可能是缺点。软件功能使用的 C++ 越多,引入的复杂性就越大,结果处理起来就变得越困难。如果开发人员只关注 C++ 的一小部分,可以避免它的许多陷阱。甚至一些公司想要完全避免这种复杂性,比如说,Linux 内核开发团队避免 C++,虽然该团队将 Rust 视为未来增添内核功能的语言,Linux 的大部分仍将用 C 语言编写。
C与Java
Java 在几十年间依旧是企业软件开发的主力军,也是整个开发界的主力军。Java 语法大量借鉴了C 和 C++。不过与 C 不同,Java 默认情况下并不编译成本机代码。相反,Java 的 JIT(即时)编译器编译 Java 代码,以便在目标环境中运行。JIT 引擎根据程序行为在运行时优化例程,从而实现了提前编译的 C 无法实现的多种优化。在适当的情况下,JIT编译的 Java 代码可以接近甚至超过 C 的性能。
而且,虽然 Java 运行时环境自动执行内存管理,但可以绕过这种处理。比如说,Apache Spark使用 Java 运行时环境的“不安全”部分来直接分配和管理内存,并避免 JVM 垃圾回收系统的开销,从而部分优化了内存中处理。
Java 奉行“一次编写,随处运行”的理念,也使 Java 程序可以在对目标架构基本不需要调整的情况下运行。相比之下,虽然 C 已经移植到许多架构上,但任何特定的 C 程序可能仍需要定制,才可以在 Windows 与 Linux 上正常运行。
这种可移植性和强大性能的结合,加上庞大的软件库和框架生态系统,使 Java 成为构建企业应用程序的首选语言和运行时环境。
Java 比不上 C 的一个方面是,C 从不旨在竞争:它靠近硬件运行,或者直接与硬件打交道。
C 代码被编译成机器代码,机器代码由进程直接执行。Java 被编译成字节码,字节码是中间代码,JVM 解释器随后将它们转换成机器码。此外,虽然 Java 的自动内存管理大体上是优点,但C更适合必须最优化使用内存资源有限的程序,因为它的初始占用空间很小。
C与Go
Go 语法很大程度上归功于 C,作为分隔符的花括号和以分号结尾的语句只是两个例子。精通 C 的开发人员通常可以直接上手 Go,即使考虑到新的 Go 功能(比如命名空间和包管理)。
确保代码可读是 Go 的指导设计目标之一:让开发人员在短时间内尽快上手 Go 项目,并熟悉代码库。C 代码库可能很难分析,因为它往往变成某个项目和团队所特有的一大堆宏指令和#ifdefs。Go 的语法及内置的代码格式化和项目管理工具旨在防止这种根本性问题。
Go 还有诸如 goroutines(协程)和channels(通道)之类的附加功能,这些语言级工具用于处理组件之间的并发和消息传递。C 需要这类功能由手工控制,或者由外部库提供,但 Go 直接就提供,因此构建需要它们的软件要容易得多。
Go 与 C 最大的底层区别在于内存管理。默认情况下,Go 对象可实现自动管理和垃圾回收。对于大多数编程工作来说,这非常方便。但这也意味着任何需要确定性处理内存的程序都将更难编写。
Go 确实包括 unsafe 包,用来避开 Go 的一些类型处理安全机制,比如读写使用 Pointer 类型的随意内存。但 unsafe 附有警告:用它编写的程序“可能无法移植,且不受 Go 1 兼容性指导准则的保护。”
Go 非常适合构建命令行实用程序和网络服务等程序,因为它们很少需要这种细粒度的操作。但是低级设备驱动程序、内核空间操作系统组件以及其他需要严格控制内存布局和管理的任务用 C 来创建再好不过了。
C与Python
如今只要一谈起软件开发,Python 似乎总是避不开。毕竟,Python 是“第二好的语言”,无疑是用途最广泛的语言之一,拥有成千上万的第三方库。
Python 强调更注重开发速度而不是执行速度,这也是它与 C 最大的不同之处。一个程序可能需要一个小时才能用另一种语言(如C)组装起来,但仅需几分钟内即可用 Python 组装起来。另一方面,该程序在 C 中执行可能需要几秒钟,但在 Python 中运行可能需要一分钟。
一个好的经验法则是,Python 程序运行起来通常比C程序慢一个数量级。但是对于现代硬件上的许多任务来说,Python 足够快了,这是它得到采用的关键。
另一个主要区别是内存管理。Python 程序完全由 Python 运行时环境管理内存,因此开发人员不必担心分配和释放内存方面的细节。但开发人员的轻松是以“运行时性能”为代价。
编写 C 程序需要严格注意内存管理,但由此生成的程序对纯粹的机器速度而言却堪称标准。
谈完区别,二者在底层却有深层的联系:参考 Python 运行时环境是用C编写的。这让 Python 程序可以包装用 C 和 C++ 编写的库。第三方库组成的 Python 生态系统有相当一部分(比如用于机器学习的第三方库)都以 C 代码作为核心。在许多情况下,这不是用 C 还是用 Python 的问题,而是涉及应用程序的哪些部分应该用 C 编写、哪些部分应该用Python编写。
如果开发速度比执行速度更重要,而且如果程序的大部分高性能部分可以被隔离到独立的组件中(而不是分散在整个代码中),那么纯粹的 Python 库或结合 Python 库和 C 库都是比单独的 C 更好的选择。但在其他方面,C 仍占统治地位。
C与Carbon
C 和 C++ 的另一个最近的竞争者是 Carbon,这是一种目前正在大力开发的新语言。
Carbon 旨在成为 C 和 C++ 的现代替代品,它有简单的语法、现代工具和代码组织技术,以及解决 C 和 C++ 程序员长期面临的问题的方案。它还旨在提供与 C++ 代码库的互操作性,因此可以增量迁移现有代码。这一切都受到欢迎,因为与最近开发的语言相比,C 和 C++ 在过去的工具和流程显得很原始很简陋。
那么有何缺点呢?目前,Carbon 是一个试验项目,尚未准备好用于生产环境。
甚至没有一个切实可行的编译器,只有在线代码浏览器。Carbon 还需要一段时间才会成为 C 或C++ 的实用替代品,如果真可以替代的话。
扫码关注公众号
获取更多技术资讯