Small. Fast. Reliable.
Choose any three.
为什么SQLite用C编码

1. C是最好的

注意:添加了本文的第2.0节和第3.0节,以响应对Hacker NewsReddit的评论 。

自2000年5月29日问世以来,SQLite一直以通用C语言实现。C曾经并且继续是实现像SQLite这样的软件库的最佳语言。目前尚无计划以任何其他编程语言重新编码SQLite。

C是实现SQLite的最佳语言的原因包括:

1.1。表现

像SQLite这样被大量使用的低级库需要快速。(并且SQLite速度很快,例如,请参阅内部BLOB与外部BLOB比文件系统快35%。)

C是用于编写快速代码的出色语言。C有时被描述为“便携式汇编语言”。它使开发人员可以在尽可能地接近底层硬件的情况下进行编码,同时仍可跨平台移植。

其他编程语言有时声称“和C一样快”。但是,对于通用编程,没有其他语言声称比C更快,因为没有。

1.2。兼容性

几乎所有系统都具有调用用C编写的库的能力。对于其他实现语言而言,情况并非如此。

因此,例如,用Java编写的Android应用程序能够(通过适配器)调用SQLite。如果SQLite是用Java编码的,那么对于Android来说可能会更方便,因为这样会使接口更简单。但是,在iPhone上,应用程序是用Objective-C或Swift进行编码的,但它们都不具有调用用Java编写的库的能力。因此,如果SQLite用Java编写,它将无法在iPhone上使用。

1.3。低依赖性

用C编写的库没有很大的运行时依赖性。在最低配置下,SQLite仅需要标准C库中的以下例程:

  • memcmp()
  • memcpy()
  • memmove()
  • memset()
   
  • strcmp()
  • strlen()
  • strncmp()

在更完整的构建中,SQLite还使用诸如malloc()和free()之类的库例程以及操作系统接口来打开,读取,写入和关闭文件。但是即使那样,依赖项的数量仍然很小。相比之下,其他“现代”语言通常需要数以千计的接口加载的兆字节运行时。

1.4。稳定

C语言是古老而无聊的。这是一种众所周知的易于理解的语言。这正是开发像SQLite这样的模块时想要的。编写一个小型,快速且可靠的数据库引擎非常困难,因为每次更新到实现语言规范时,实现语言都不会从您身旁改变。

2. SQLite为什么不使用面向对象的语言编码?

一些程序员无法想象使用不是“面向对象”的语言来开发像SQLite这样的复杂系统。那么为什么SQLite没有用C ++或Java编码?

  1. 用C ++或Java编写的库通常只能由以相同语言编写的应用程序使用。很难获得用Haskell或Java编写的应用程序来调用用C ++编写的库。另一方面,可以用任何编程语言调用用C编写的库。

  2. 面向对象是一种设计模式,而不是编程语言。您可以使用所需的任何语言(包括汇编语言)进行面向对象的编程。某些语言(例如C ++或Java)使面向对象的工作变得更加容易。但是您仍然可以使用C之类的语言进行面向对象的编程。

  3. 面向对象并不是唯一有效的设计模式。许多程序员被教导纯粹根据对象来思考。而且,公平地说,对象通常是分解问题的好方法。但是对象不是唯一的方法,也不总是分解问题的最佳方法。有时,好的旧程序代码比面向对象的代码更容易编写,维护和理解,并且速度更快。

  4. 最初开发SQLite时,Java是一种年轻且不成熟的语言。C ++较老,但经历了越来越大的痛苦,以至于很难找到任何两个以相同方式工作的C ++编译器。因此,当最初开发SQLite时,C绝对是更好的选择。现在情况已经不那么明显了,但是此时重新编码SQLite几乎没有好处。

3.为什么SQLite不能用“安全”语言编码?

近来,人们对“安全”编程语言(如Rust或Go)产生了浓厚的兴趣,在这种语言中,不可能或至少很难造成常见的编程错误,例如内存泄漏或数组溢出。因此,经常会出现一个问题,为什么SQLite不能以“安全”语言进行编码。

  1. 在SQLite诞生的头十年,没有一种安全的编程语言存在。可以在Go或Rust中对SQLite进行重新编码,但这样做可能会引入比已修复的错误更多的错误,而且似乎也可能导致代码变慢。

  2. 安全的编程语言解决了简单的问题:内存泄漏,释放后使用错误,数组溢出等。安全的语言在解决计算SQL语句正确答案这一更为困难的问题上没有提供任何普通C代码以外的帮助。

  3. 人们经常吹捧安全语言,以帮助防止安全漏洞。的确如此,但是SQLite并不是一个特别安全的库。如果应用程序正在运行不受信任和未经验证的SQL,则它已经具有更大的安全性问题(SQL注入),无法解决“安全”语言。

    的确,应用程序有时会从不受信任的源中导入完整的二进制SQLite数据库文件,并且此类导入可能会带来可能的攻击媒介。但是,SQLite中的这些代码路径是有限的,并且经过了很好的测试。而且,预验证例程可用于希望读取不受信任的数据库的应用程序,这些数据库可以帮助在使用前检测可能的攻击。

  4. 一些“安全”语言(例如Go)不喜欢使用assert()。但是使用assert()是保持SQLite可维护性的重要组成部分。就SQLite的开发人员而言,Go中缺少assert()是一个阻碍因素。有关 其他信息,请参见在SQLite中使用assert()

  5. 安全语言会插入其他机器分支来执行诸如验证阵列访问是否入站之类的操作。用正确的代码,这些分支将永远不会被使用。这意味着无法对机器代码进行100%分支测试,这是SQLite质量策略的重要组成部分。

  6. 如果安全语言遇到内存不足(OOM)的情况,通常希望中止。SQLite旨在从OOM正常恢复。目前尚不清楚如何在当前的安全语言中实现这一目标。

  7. 现有的所有安全语言都是新的。SQLite的开发人员赞扬计算机语言研究人员在尝试开发更易于安全编程的语言方面所做的努力。我们鼓励继续努力。当我们实现SQLite时,我们自己对旧的无聊的语言更感兴趣。

综上所述,SQLite可能有一天可能会在Rust中进行重新编码。由于Go讨厌assert(),因此不太可能在Go中重新编码SQLite。但是Rust是可能的。在Rust中重新编码SQLite之前必须发生的一些前提条件包括:

  1. Rust需要再成熟一点,停止这么快地改变,并进一步变老和变得乏味。
  2. Rust需要证明它可以用于创建可从所有其他编程语言调用的通用库。
  3. Rust需要证明其可以生成在晦涩的嵌入式设备(包括缺少操作系统的设备)上运行的目标代码。
  4. Rust需要选择必要的工具,以使人们能够对已编译的二进制文件进行100%的分支覆盖率测试。
  5. Rust需要一种机制来从OOM错误中正常恢复。
  6. Rust需要证明它可以完成C在SQLite中所做的工作,而不会明显降低速度。

如果您是“ rustacean”,并且认为Rust已经满足上面列出的前提条件,并且应该在Rust中重新编码SQLite,那么欢迎您并鼓励您私下联系SQLite开发人员并讨论您的情况。