是的,你仍然应该学习 C

是的,你仍然应该学习 C

Linus Torvalds, creator of the Linux kernel and outspoken defender of the C programming language.

我想看到我文章的大多数人都是网络开发人员、游戏开发人员或桌面软件工程师。这很好,但这意味着你们使用的大多数语言都是机器代码之上的一些抽象; Java 和 C# 是严格的面向对象的语言,它们迫使你进入那种设计范式,而 JavaScript 是……嗯,一种 绝对的噩梦 .很容易陷入高级代码的世界,陷入一切都需要是一个类的心态,我们需要 20-25 个 .cs 文件来创建一个简单的 Web API。企业之所以喜欢这些语言,很大程度上是因为它们易于学习、易于阅读,并且可以轻松地跨多个平台部署或作为 Web 应用程序轻松部署。然而,这是一个残酷的事实——作为一名工程师,严格遵守高级 OO 语言是在损害自己的利益。

与流行的看法相反,C 并没有死——远非死了。它仍然广泛用于嵌入式软件和各种企业项目,但在内核和操作系统设计领域尤为突出。 Linux 是开源内核,通常与各种自由软件 (GNU/Linux) 打包在一起,是迄今为止在服务器上最常见的操作系统,并且它作为日常驱动的桌面操作系统的采用率一直在稳步增加。现在是学习 C 的最佳时机,特别是考虑到 GNU 的创建者和自由软件基金会的杰出代表 Richard Stallman 最近发布了一份相当强大的 GNU/Linux 环境下的 C 编程指南。

本文旨在介绍 C 语言中的一些基本概念,解释其实用性,并消除有关所谓的面向对象语言的“优势”的谣言。

你不需要类或对象(可能)

This allows us to instantiate a new ListNode on the heap like so: Key features of a struct in C

自从 OOP 范式出现以来,关于编程语言中面向对象设计的争论就一直激烈而无休止。我不会在本文中告诉您 OOP 是“好”还是“坏”。它是一种特定的范式,在某些情况下有用,而在其他情况下用处不大。然而,人们很容易争辩说,它已被广泛采用,并应用于不需要其应用的软件设计场景。例如,您的普通 Java 程序员可能会将他编写的几乎所有内容捆绑到一个类中,即使将他的应用程序的大部分核心功能留在全局范围内也可以正常工作。

这将我们带到了面向对象设计的边缘,但也很诱人——函数式编程、过程式编程和命令式编程。面向对象的语言 能够 支持这些设计模式并且经常这样做,也许最恰当的例子是 C# 支持功能设计以及类和对象的使用。然而,其他语言要么强烈反对或完全禁止使用除 OO 设计之外的任何东西,Java 是这方面最令人震惊的例子之一,因为它严重依赖给定程序中几乎所有东西都是类。

C 允许您保持有条理并使用我们通常理解为对象的几个关键特性,而无需完全采用类和对象的语言。通过使用结构,我们可以将关联的数据和内存指针捆绑到一个类型中(一个 la 封装),以后可以根据应用程序的要求在堆上重用或实例化为内存。以单链表中的节点为例:

 typedef 结构列表节点 {  
 整数键;  
 结构 ListNode* 下一个;  
 }列表节点;

如果您曾经使用过链表数据结构,那么这应该非常熟悉。我们有一个类型叫做 列表节点 它包含两个字段,一个键表示节点中包含的数据,类型为 int,另一个指针指向堆上的另一个 ListNode,即链表中的下一个节点。我们给它修饰符 类型定义 表示我们希望稍后在我们的程序中使用此结构,而不必将其限定为 结构。 这允许我们在堆上实例化一个新的 ListNode,如下所示:

 ListNode* create_node(int key) {  
 ListNode* newNode = malloc(sizeof(struct ListNode));  
 (*newNode).key = key;  
 (*newNode).next = NULL;  
 返回新节点;  
 }

请注意,在我们的节点名称之前使用取消引用星号 () 等效于箭头语法。这只是 somListNode create_node(int key) {
ListNode* newNode = malloc(sizeof(struct ListNode));
(newNode).key = key;
(
newNode).next = NULL;
返回新节点;
} 通常通过在另一种语言中使用类来完成的事情可以在 C 中同样有效地复制(并且可以说,更清晰),而无需存在类或对象。在本例中,您可以处理 malloc 类似于 新的 像 C++ 或 Java 这样的语言中的运算符——它只是在堆上为给定类型分配必要的内存。请记住,C 没有垃圾收集器——您必须使用以下函数手动管理堆上的内存 malloc自由的 .

几乎无与伦比的性能

A chart showing median time necessary for common programming languages to calculate through the Leibniz formula a certain number of times. Source: https://github.com/niklas-heer/speed-comparison

程序员早就承认,为了让使用某种语言不被激怒,需要牺牲某些东西。举个例子,Java 永远不会胜过 C++,但大多数人都觉得这很好,因为 C++ 是出了名的极其乏味且难以用作通用语言。从本质上讲,Java 程序员正在牺牲性能来换取可读性和可用性。但是,如果你不必牺牲任何东西呢?如果您可以在保持清晰、简洁的句法规则和极高可用性的同时获得一流的性能会怎样?这就是 C 的用武之地。

C 已经形成了一种“硬”语言的声誉,但这种声誉是非常值得怀疑的。几乎所有被广泛采用的现代语言——Java、C#、C++、Python 等——在其基础上都是基于 C 的设计和语法。几乎任何使用高级语言编程的人都可以快速开始用最少的时间用 C 语言开发程序;事实上,他们可能会发现它比大多数其他语言更简单,因为它避免了许多与面向对象设计相关的陷阱。 C 语言最困难的两个方面,即内存管理和(相当陈旧的)语法,确实是一项时间投资。然而,它们并不比一门新语言的任何其他方面更难学习。

作为采用一些编写代码的新思维方式的交换,C 为您提供了同类最佳的性能,其后继者 C++ 甚至都无法与之匹敌。在上图中,唯一能够与 C 相匹敌的语言是 Go,这是一种专门为复制 C 中存在的许多特性和设计技术而创建的语言。您可能会注意到表现最好的语言是最接近 C 的语言。例如,C++ 本质上是带有附加语法规则和特性的 C,Python 的解释器是用 C 编写的(因此默认实现称为 CPython)等等。C++ 可能在视频游戏行业中得到更广泛的采用,但这可能是因为它在 Unreal Engine 等软件中的使用(实际上需要使用类);许多游戏和高性能软件都是用 C 语言制作的,有时甚至没有使用第三方库。

为什么不直接使用 C++?

A visual representation of the relationships between C, C++, and Java in terms of shared features, design patterns, syntax, etc.

在对 C 语言赞不绝口之后,一些读者可能想知道为什么要使用 C 而不是其继任者 C++。造成这种情况的原因有很多,但与往常一样,这取决于您打算创建什么以及您的具体用例。但是,这里是 C 相对于 C++ 的(上下文)优势的简要列表:

  • C在理论上具有更好的性能。
  • C 可以说具有更清晰、更易读的语法;它仅限于一组相当有限的库和特性,使其环境比广泛而强大的 C++ 更容易理解。
  • C 理论上更易于在“接近金属”的情况下使用和编译(操作系统/内核设计、嵌入式系统等)
  • C 的编译时间比 C++ 快。
  • C与其他语言有更好的互操作性;某些语言甚至允许您直接从该语言中调用 C 函数。使用 C++ 实现这一点要困难得多。
  • 因为 C++ 更复杂,更难有效地“学习”,所以比在 C 中更容易犯错误或产生使应用程序瘫痪的错误。这是 Linus Torvald 对 C++ 的著名咆哮的症结所在,主要关注如何它激发了糟糕的程序设计。

希望你“C”我的观点

如果我给您留下了任何东西,那么希望它是学习 C 并开始用它编写程序的动力。然而,有些想法最好通过歌曲来表达,因此我把这个杰作留给你:

如果您在 C 中开发了任何简洁的东西,请务必让我知道!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/36044/07201408

posted @ 2022-09-14 08:08  哈哈哈来了啊啊啊  阅读(7)  评论(0编辑  收藏  举报