【AICon】AI 基础设施、LLM运维、大模型训练与推理,一场会议,全方位涵盖! >>> 了解详情
写点什么

今时今日,C 还适合当下之所需么?

  • 2013-01-27
  • 本文字数:4636 字

    阅读完需:约 15 分钟

来自 Couchbase 的 Damien Katz 认为 C 依然是非常适合于后端编程的一门语言,然而有的开发者则觉得 C 有太多的瑕疵,他们支持 C++ 或是 Java,还有一些人连这两种语言也不喜欢。

在最近一篇题为 The Unreasonable Effectiveness of C 的博文中, CouchDB 的创建者 Damien Katz 表示 C 依然是非常适合于后端编程的一门语言,虽然现在已经有了很多更加现代化的语言,如 C++、Java、甚至是 Erlang 或是 Ruby,但他还是非常支持 C 语言。Katz 并不是认为 C 就是比其他任何语言都要好,但在“重点考虑性能与可靠性等场景下,C 是很难被打败的”——这段话援引自 Damien Katz 随后的一个帖子,旨在澄清自己的立场

虽然一开始使用 Erlang 编写了 CouchDB 的很多代码,但在花费了“2+ 个人月来处理 Erlang VM 中的一个崩溃问题”之后,Katz 感到非常不爽。

我们浪费了大量时间追踪核心 Erlang 实现中的一些问题,不敢保证发生什么以及原因,我们觉得也许问题出现在我们自己的插件 C 代码中,希望我们自己能够发现并修复问题。但事实并非如此,这是核心 Erlang 中的一个竞态条件 Bug。我们只能通过 Erlang 的代码查看器来找到这一问题。对于那些对计算机进行了过多抽象的编程语言来说,这是个很基本的问题。

出于这一点以及性能因素,Katz 决定逐步重写,“将 Couchbase 的代码换成 C,并将其作为大多数新特性的首选实现语言”。有趣的是,C 证明了“当我们遇到问题、调试与修复问题时,C 更具备可预测性。长远来看,C 的生产力更高”。

Katz 列出了对于后端来说,C 要优于更高层次语言如 C++、Java 等的若干原因:

  • 表现力——“C 的语法与语义非常强大且具有极强的表现力。凭借 C,我们既能预测高层算法,又能预测低层的硬件。它的语义非常简单,语法足够强大,能够极大降低认知上的负担,让程序员专注在重要的事情上”。
  • 简单——“C 是一种弱、静态类型语言,其类型系统非常简单。我们所说的弱最后会变成一个优点:C APIs 的“表面”是非常简单且小巧的。相对于大多数框架来说,C 的一个明显趋势与文化就是创建小型的库,对简单类型进行轻量级的抽象”。
  • 速度与内存使用——“C 是速度最快的语言,无论是部分还是完整的基准都表明了这一点。它不仅仅运行时是最快的,其内存使用与启动时间也是效率最高的。如果需要在空间与时间上进行折衷,那么 C 并不会对你隐藏任何细节信息,我们可以很容易地做出估计”。
  • 更快的开发周期——“对于开发者效率与生产力来说最为重要的就是‘构建、运行与调试’周期。周期越快,开发的交互性就越好,你就更容易处在任务的流态上。相对于所有主流的静态语言来说,C 拥有最为快速的开发交互性”。
  • 调试——“对于纯 C 代码来说,你可以查看调用堆栈、变量、参数、线程局部变量、全局变量,基本上可以查看到内存中的一切。这是非常有用的,特别是当你遇到了问题,这个问题在运行的服务器进程中出现了多日,并且无法重现的情况下更是如此。如果在更为高层的语言中失去了这个上下文,那么你就等着痛苦去吧”。
  • 跨平台——“有一个标准化的应用二进制接口(ABI),可为现有的所有操作系统、语言与平台所支持。它无需运行时,也不需要其他额外内容。这意味着你使用 C 所编写的代码并非仅仅可由 C 代码中的调用者所调用,还可以由现有的所有库、语言与环境所调用”。

Katz 也认为 C 有“很多瑕疵”:

没有范围检查,不小心就会导致内存出现问题、存在野指针与内存 / 资源泄露情况、对并发的附加支持、没有模块、没有命名空间。错误处理非常麻烦且冗长。很容易就会搞出一堆错误,调用堆栈也找不到了,恶意输入会控制你的进程。闭包?哈哈

Katz 对 C 的强烈偏爱源自突破 Couchbase 性能极限的需求以及调试问题(问题是 C 插件与 Erlang VM 联合使用所导致的)。他并不认为 C++、Go 或是 D 能够替换 C,但他认为 Rust 可能会成为“梦想之语言”,只要它能实现“类似于 C 的性能而且能够做到与 Erlang 安全的并发和内建的健壮性”。

Katz 的帖子在 Reddit Hacker News 上可谓是一石激起千层浪,有很多开发者谈到了 C 的优点,也有人建议其他语言。 robinei 加入到了字符串操作与错误检测激战当中:

我总想回到 C(从 C++ 等语言中),当我真的这么做了时,我发现不少地方通常都是很简单的,感觉真棒! 但接下来我需要进行字符串操作,或是这类笨拙的方法。

这时会出现很多分配操作,每一个都需要一个显式的 free 搞得我太痛苦了。我尝试通过 arena allocators 树来解决这个问题,就像 Go 中的 slice-strings,但最终 C 还是缺乏一些语法工具(命名空间前缀函数),这导致结果变得非常笨拙(将一切都分配到 arenas 中也是非常痛苦的)。

我发现由于要进行显式的错误检测,源代码文件长度增加了一倍(这种情况不常发生,但在诸如 sqlite 等一些库中,任何操作都有可能失败)。

还有很多方面导致我精疲力竭,我觉得非常不满意。

综上所述,我从哪儿来的还是回哪儿去吧,通常是 C++。

madhadron 提出了“更加现实的 C ”:

C 能够在 PDP-11 上很直接地编译成快速的机器码。 C 的标准库就是个笑话。它的缺点,特别是字符串相关的处理,是过去 40 年众多安全漏洞的罪魁祸首。

C 的工具根本不值得吹嘘,特别是与同辈的 Smalltalk 和 Lisp 相比。人们所使用的大多数 C 调试器都是命令行。根本没法和 Squeak 或是 Allegro Common Lisp 的标准调试器相比。

声明快速的 C 构建 / 调试 / 运行周期令人沮丧。表面上看起来很快,因为 C++ 在这个领域是失败的。如果你想知道如何加快构建 / 调试 / 运行周期,那么请看看 Turbo Pascal 吧。

你可以通过标准 ABI 在所有 Unix 上调用 C,虽然这么说没错,但原因却是因为 C 的普遍存在性而已。

geophile 对上述内容持不同看法

C/C++/Java,这是程序员视角的石头 / 剪刀 / 布。 多年以前,我从 C 开始,我发现自己用宏和库为声明与函数提供了很多很有用的组合。我发明了对象,同时也发现了 C++。

长久以来,我一直是个快乐的 C++ 用户,很早就开始了(还是 cfront 时代)。但我被语言的复杂性搞崩溃了,特别是特性之间微妙的交互,我厌倦了内存管理,渴望 Java,而它又适时地出现了。

我很开心。在学习语言时,我肯定我漏掉了某些东西。每个对象都在堆中么?真是如此么?真的没有办法将一个对象在物理上嵌入到另一个对象中么?但其他一切都很棒,我不介意这一点。

现在我在编写一些系统,这些系统会占用很多内存,包含成千上万的对象,有些对象很小,有些则很大。每个对象的代价快要搞死我了。GC 调优是个梦魇,我正在实现子分配模式。我编写了微基准,比较普通对象与序列化为字节数组的对象。由于 C++ 已经变得太恐怖了,比令我焦头烂额的早期版本还要复杂,因此我又渴望 C 了。

现在的我不再喜欢任何语言了。

对于某些人来说,C 看起来瑕疵太多,已经不适应现代的生产力要求了,但还有不少人依然能够很好地使用 C,尽管它有很多怪癖。开发者社区还是应该避免语言之争,而是更好地权衡每一种语言,根据项目需求与自身技能选择最合适的语言。毕竟,没有一种语言是完美的。

此文在 InfoQ 英文站也引来了众多读者的讨论,下面摘取部分读者的评论供大家参考。

读者 Mark Peskin 说到:

嗯,我喜欢 C。它很简单,没有 C++ 那些庞大且有瑕疵的面向对象特性。然而,使用 C 编写大型、可扩展、模块化的企业应用需要大量规则,这些规则在大型的软件企业中几乎是无法维护的。我认为 C 的一个问题是它会引诱聪明的开发者编写高度优化的代码,充满了 memcpy() 与指针运算,以此“打败编译器”,这对于其他开发者来说几乎无法理解(如果不信,你去读读 BSD 内核代码吧)。 总的来说,如果有很多开发者在开发大型、复杂且长期的项目,那么我认为你最好使用 Java(或是 Scala 等语言)。将 C 用在那些偶尔出现的场景中吧,这时你可能真的需要本地代码,使用基于消息的系统将二者集成起来(JNI 不行)。C++?还是算了吧。

读者 Josh Long 说到:

回应 Katz 关于 C 的问题。 我同意 Mark 的观点,在某种程度上,也认可 Damien 的看法。

Damien 提到的一点是我们很少在 C 中看到真正大型、全面的框架,比如 APIs。如果构建小型、某个方面的 API(通过一些 typedefs/structs 与函数作为“契约”),那么我们可以很轻松地将库“导出”并重用。我觉得这是 C 最适合之处。我从来不会因为性能问题而使用 C,但使用 C 实现某些功能则是更为轻松的事情(内核编程、嵌入式编程、处理硬件、所依赖的 APIs 并未在更高层次的语言如 Java、Ruby、Python 等进行过抽象的功能)。

我还尽量不使用 C 编写具有完整功能的系统,只是因为它对于大型项目来说不具备“可伸缩性”。使用 C 编写的大型项目最终的结果都是重新编写了很多东西(比如说对象与命名空间等)。恕我直言,真的没有多少领域需要从头到尾都用 C 不可。当然了,一些例外是系统级组件,比如说操作系统(Linux)或是 UI,如 GNOME。但对于应用来说,使用更高层次的语言,在高层次语言与平台之间存在缝隙之处再使用低层次 APIs 进行集成是更容易的做法。Java 存在很多这类“缝隙”,但随着 APIs 逐步成为很多不同操作系统上的常客后,在过去 10 年间,有些已经被逐步解决了:事件驱动的 IO、文件系统通知、文件权限与元数据等等。

Mark 为集成 C 库与模块提出了很好的解决方案。他认为 JNI 不行,建议使用消息。我是消息的忠实粉丝。本质来说,成功使用消息与成功使用 JNI 都需要同样的东西:你需要彻底简化导出 API。

在使用 JNI 时,绝不要将任何复杂的 C 类型“泄漏”到我的 Java API 中,反之亦然,并且总是通过数值类型与 char* -> jstrings 进行通信。即便我所公开的本地代码是用 C++ 编写的,我也依然会使用 C 风格的 JNI(而不是 C++),因为这种规范化有利于互操作。如果保持 C API 表面的简洁性,并且避免线程,那么通过 Java JNI、CPython 或是 MRI Ruby 等可以将其作为本地扩展。

一旦完成了这个过程,接下来通过消息公开 C API 就变得很简单了,因为根据定义,两个系统之间的消息负载不可能比 C 库还要复杂。当然了,如果使用消息,这意味着要么使用 C 编写消息代码,要么将 C 库公开到更高层的语言上,并在那里实现消息。消息好的一面是能够将高层语言代码与 C 代码进行隔离,这么做会比 Java 代码要薄一些。我依然不会直接将使用 C APIs 编写的代码链接到我的应用中。如果 C 代码挂掉了,那么消息系统就会接收请求,直到运行着 C 代码的另一个节点能够进行处理为止。另一方面,如果真的因为性能原因而使用 C,那么消息至少会引入一个网络传输,更不必说系统中的另一个组件了,这么做就抵消了使用 C 编码所带来的优势了。在这种情况下,我们可以编写稳定、行为良好的 JNI 或是本地扩展,但还是需要保持表面的小巧,并且理解前置与后置条件才行。没有线程。不要在 C 与 Java 之间传递指向复杂对象的指针。请确保你自己清楚谁来负责清理内存,什么时候清理。

总而言之,忘掉 C++ 吧。

读者 Bernd Kolb 说到:

或许你想要看看 mbeddr( mbeddr.com )。 mbeddr 旨在更好地支持嵌入式软件开发(但并不仅仅限于此),针对基于 C 语言与 IDE 的可扩展版本的小型与大型系统。现有扩展包括前置和后置的接口、组件、状态机与物理单元,以及对需求追踪和产品线变化的支持。基于这些抽象,mbeddr 还支持基于模型检测与 SMT 处理的形式验证。

通过这种方式,在大型项目与团队中,C 也可以做到“可伸缩”。此外,我们还可以引入现代的编程规则。通过扩展 mbeddr,你甚至可以为消息等添加基础信息。

查看英文原文: Is C Still A Suitable Language Today?

2013-01-27 05:554877
用户头像

发布了 88 篇内容, 共 258.7 次阅读, 收获喜欢 8 次。

关注

评论

发布
暂无评论
发现更多内容

SUFS: 存储资源使用量预测服务

KaiwuDB

KaiwuDB 存储资源使用量预测

ABAQUS下载-ABAQUS软件官方版教程下载

思茂信息

abaqus abaqus软件 abaqus有限元仿真 有限元分析 有限元仿真

王海峰最新发声!

TE智库

百度 文心一言

2023广州国际跨媒体技术及设备展览会

吹吹晚风

一次说清楚:CAE软件可以做什么?

智造软件

CAE 仿真软件 有限元仿真技术 有限元分析 CAE软件

一文带你上手Servlet

EquatorCoco

Java 前端

用友BIP数智化底座使能行业创新发展

用友BIP

数智底座

Python第三方库(包)的安装(windows系统)

MEImei

华为云5大开源项目发布与更新,助力开发者实现应用创新

华为云开发者联盟

开源 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

MobPush 工作台操作指南:查看推送数据

MobTech袤博科技

大数据 前端 后端

喜报:数划云通过华为鲲鹏技术认证,助力信创国产化进程

数划云

华为 鲲鹏 全面预算 数划云

衡量开发人员工作效率的五个技巧

高端章鱼哥

代码 代码开发 开发效率

小红书2024届REDstar技术提前批招聘火热进行中,快喊上学弟学妹看过来!【附专属内推码】

小红书技术REDtech

技术 招聘 校招 小红书

Java 踩坑 1|Spring 事务导致多数据源切换失败

itschenxiang

Java’ 业务开发

PCB防静电设计的必要性

华秋PCB

工具 PCB PCB设计 电压 防静电

一文看懂基础模型的定义和工作原理

这我可不懂

人工智能 机器学习 基础模型 GPT

使用GithubAction自动构建部署项目

EquatorCoco

前端 Github Action 框架模式

中字头企业数字化转型的挑战与机遇

用友BIP

国产替代

软件测试/测试开发丨Windows Appium环境搭建

测试人

程序员 软件测试 自动化测试 环境搭建 appium

2024上海国际消泡剂技术展览会

吹吹晚风

2023年值得学习的六种小众编程语言

互联网工科生

编程语言 开发语言

字节跳动开源 Kelemetry:面向 Kubernetes 控制面的全局追踪系统

字节跳动开源

Kubernetes 云原生 可观测 追踪系统

2023广州国际智慧机房及综合布线展览会

吹吹晚风

Web3 开发指南:使用 NFTScan NFT API 构建一个 NFT 链上追踪器

NFT Research

Web3 Daily API NFT\

掌握把“烂”SQL牢牢关进笼子里的密钥

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

用友新一代票据云,实现企业票据“支付找零”

用友BIP

全球司库

软件测试/测试开发丨Mac Appium环境搭建

测试人

程序员 软件测试 Mac appium

盘古大模型加持,华为云开天aPaaS加速使能千行百业应用创新

华为云开发者联盟

云计算 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

谈一谈LLM在推荐域的一些理解

阿里技术

大模型 AIGC

纯代码和低代码的本质区别

互联网工科生

软件开发 低代码 代码开发

30多款大模型亮相,现阶段厂商比客户更需要大模型 | WAIC2023探展

TE智库

人工智能 大模型 WAIC

今时今日,C还适合当下之所需么?_Java_Abel Avram_InfoQ精选文章