多年来,我一直竭尽全力摆脱C。太简单了,要处理的细节太多,太老旧又脆弱,太低级了。我曾经与Java,C ++和Erlang发生过激烈而又热恋的爱情。我创造了令我引以为傲的事物,但每一件事都伤透了我的心。他们做出了他们无法兑现的承诺,建立了专注于错误事物的文化,并进行了破坏性的折衷,最终使您遭受痛苦。这使得我又一直爬回C。
C是总包装。它是唯一一种生产率高,速度快,在任何地方都具有出色的工具,庞大的社区,高度专业的文化,并且真正权衡取舍的语言。
其他语言可以使您更快地进入工作状态,但是从长远来看,当性能和可靠性很重要时,C可以节省您的时间和麻烦。我很痛苦地再次学习这一课。
简单而富有表现力
C是一种很棒的高级语言。我再重复一遍。C是一种很棒的高级语言。它不像Java或C#那样高级,当然也不像Erlang,Python或Javascript那样高级。但这和C ++一样高级,而且要简单得多。当然,C ++提供了更多的抽象概念,但是它并没有提供比C语言更高级的抽象概念。使用C ++,您仍然必须了解C方面的所有知识,以及许多其他荒谬的东西。
我们很难考虑使用较低级别的语言来代替C,这并不是因为C是低级的。这是因为C作为对基础机器的抽象而获得了如此大的成功,并使其成为高级语言,因此使大多数低级语言均无关紧要。C擅长于其功能。
C的语法和语义非常强大且富有表现力。它使得同时推理高级算法和低级硬件变得容易。它的语义是如此简单,而语法却如此强大,以至于大大降低了认知负担,从而使程序员可以专注于重要的事情。
更简单的代码,更简单的类型
C是一种弱类型的静态类型语言,其类型系统非常简单。与C ++或Java不同,您没有用于定义各种类型的新运行时行为的类。您几乎仅限于结构体和联合体,并且所有调用方必须非常明确地了解它们如何使用类型。
听起来像弱点的东西最终成为一种优点:C API的“表面积”趋向于简单而又小。代替大型框架,有一种强烈的趋势和文化来创建小型库,这些库是对简单类型的轻量级抽象。
与此相反,OO语言中的代码库倾向于发展大量复杂类型的相互依赖的接口,其中参数和返回类型是更复杂的类型,复杂性是分形的,每种类型都是根据具有参数和返回类型或更多类型的方法定义的类。复杂的返回类型。
并不是说OO类型的系统迫使分形复杂性发生,而是鼓励这样做,它们使做错事情更容易。C不会使它变得不可能,但是会使它变得更加困难。C趋向于产生更简单,更浅的类型,具有更少的依赖关系,这些依赖关系更易于理解和调试。
速度王
无论是在微型还是全栈基准测试中,C都是目前最快的语言。它不仅是运行时最快的,而且始终是内存消耗和启动时间最高效的工具。而且,当您需要在时间和空间之间进行权衡时,C不会向您隐藏细节,因此很容易就这两者进行推理。
每当更高级别的语言(例如Java或Haskell)声称具有“接近C”的性能时,当您看到详细信息时,这就会变成一个恶心的笑话。他们不得不笨拙地使用语法,使用“智能”编译器和VM内部组件的特殊知识来获得这种性能,以至于该语言的简单表达性被特定于版本的奇怪优化所遗忘,并且通常只能使用在微基准测试中
当您使用C语言编写快速的东西时,您就会知道为什么它如此之快,并且在不同的编译器或环境下,它不会像不同的VM那样显着降低性能,GC设置可以从根本上影响性能和暂停,或者与之交互应用程序中的一段代码将完全改变其余部分的垃圾收集配置文件。
用C语言进行优化的途径是直接而简单的,当不是这样时,有许多探查器工具可帮助您理解为什么,而不必了解VM或“足够智能的编译器”的精髓。在将分析器用于CPU,内存和IO时,C不会掩盖实际情况。该基准测试,微观和完整的堆栈,始终证明C是仍然是国王。
更快的构建,运行,调试周期
对开发人员的效率和生产率至关重要的是“构建,运行,调试”周期。周期越快,开发越具有交互性,并且您在流程和任务状态中的停留时间就越多。C具有所有主流静态类型语言中最快的开发交互性。
因为构建,运行,调试周期不是语言的核心功能,所以更多的是围绕它的工具,因此这个周期通常会被忽略。很难夸大周期对生产力的重要性。遗憾的是,大多数编程语言讨论都忽略了这一点,在这些讨论中,重点往往仅放在代码行和源可写性/可读性上。现实情况是,C的工具和交互周期是所有同类语言中最快的。
无处不在的调试器和有用的故障转储
对于几乎任何您想移植到的系统,都有现成的C调试器和崩溃转储工具。这些对于快速找到问题根源非常宝贵。
使用任何其他语言,可能都没有可用的调试器,而不太可能使用有用的崩溃转储工具,而且无论如何,您与C代码进行交互的繁重工作确实有很大的机会。现在,您必须调试其他语言和C代码之间的接口,并且常常会丢失大量上下文,这使其成为一个麻烦且容易出错的过程,并且在实践中通常完全没有用处。
使用纯C代码,您可以看到调用堆栈,变量,参数,线程局部变量,全局变量,基本上是内存中的所有内容。这特别有用,特别是当您在长时间运行的服务器进程中出现某些问题而无法重现时。如果您在高级语言中失去了这种上下文,请为痛苦做准备。
随时随地均可调用
C具有标准化的应用程序二进制接口(ABI),该接口已存在的每种操作系统,语言和平台都支持。而且它不需要运行时或其他固有开销。这意味着您使用C语言编写的代码不仅对使用C代码的调用者有价值,而且对于存在的每种可能的库,语言和环境也很有价值。
您可以在独立的可执行文件,脚本语言,内核代码,嵌入式代码中将C代码用作DLL,甚至可以从SQL调用。它是系统编程和可插入库的Lingua Franca。如果您想编写一次内容并使其在大多数环境和用例中都可以使用,那么C是唯一明智的选择。
是的。它有缺陷
C中有许多“缺陷”。它没有边界检查,很容易破坏内存中的任何内容,有悬空的指针和内存/资源泄漏,对并发的狂热支持,没有模块,没有命名空间。错误处理可能非常麻烦且冗长。在调用堆栈被破坏并且敌对的输入接管您的过程时,很容易产生一整类错误。
它的缺陷非常众所周知,这是一种美德。所有语言和实现都有缺点。C只是有关它的事而已。并且有大量的静态和运行时工具可以帮助您处理最常见和最危险的错误。世界上一些使用最频繁,最可靠的软件是基于C的,这证明了这些缺陷是过分夸张的,并且易于检测和修复。
在Couchbase,我们最近轻松地花费了2个人/月来处理Erlang VM的崩溃。我们浪费了大量的时间来跟踪Erlang核心实现中的某些内容,永远不确定发生了什么或为什么,认为缺陷是我们自己的插件C代码中的某些东西,希望可以找到并修复它。并非如此,这是核心Erlang中的一个竞赛条件错误。我们仅通过对Erlang的代码检查发现了问题。对于任何一种抽象的计算机来说,这都是一个基本问题。
最初出于性能原因,我们开始越来越多地用C重写更多的Couchbase代码,并选择它作为更多新功能的首选。但是令人惊讶的是,当我们遇到问题以及如何调试和修复问题时,事实证明它具有更强的可预测性。从长远来看,它会提高生产力。
我总是想把C做得更好一点。只是清理一些粗糙的边缘并解决一些更严重的问题。但是,要使所有内容都适合,自上而下,语法,语义,工具等,这是不可能的,甚至也不值得付出努力。就目前的情况而言,C是无理的但是有效,而且我认为这种变化不会很快改变。
领取专属 10元无门槛券
私享最新 技术干货