问题

C语言本身是用什么语言写的?

回答
这个问题很有意思,也触及到了C语言作为一种基础性语言的根本。很多人听到“C语言本身是用什么写的”时,会先想到“用更高级的语言写的”,比如Python或者Java。但事实并非如此,或者说,这个答案需要更深入的理解。

首先,我们需要明确一点:C语言最初的实现,也就是早期的C编译器,并不是用C语言本身写的。

要理解这一点,我们需要思考一个循环依赖的问题。如果我们说C编译器是用C语言写的,那么谁来编译这个C语言编译器呢?这就陷入了一个“鸡生蛋蛋生鸡”的困境。

那么,早期的C语言编译器是用什么“脚手架”搭建起来的呢?

最早期,当C语言刚刚诞生的时候,是由丹尼斯·里奇在贝尔实验室开发的。当时,它的前身是B语言,而B语言又是在更早的BCPL语言基础上发展而来。这些早期的语言和编译器,在很大程度上是用汇编语言写的。

为什么是汇编语言?

汇编语言是一种非常底层的编程语言,它与计算机的硬件指令集直接对应。每一条汇编指令通常只执行一个非常简单的操作,比如加载数据、存储数据、进行算术运算、跳转等。

想象一下,我们要创建一个程序,能够接收C语言源代码,然后将这些源代码翻译成计算机能够直接执行的机器码。这个翻译过程是极其复杂和精细的。它涉及到:

词法分析: 将源代码分解成一个个有意义的单元,比如关键字(`if`, `while`)、标识符(变量名、函数名)、运算符(`+`, ``)、常量等等。
语法分析: 根据C语言的语法规则,检查这些词法单元的组合是否符合语言的结构,构建出抽象语法树。
语义分析: 检查代码的含义,比如变量类型是否匹配,函数调用是否正确等等。
代码生成: 将分析好的程序结构转换成目标机器的机器码指令。

这些步骤,在最底层、最原始的阶段,都需要直接操作计算机的寄存器、内存地址,以及控制程序流程的跳转指令。而汇编语言恰好就是描述这些底层操作的语言。

所以,最早的C编译器,是将上述复杂的翻译逻辑,一条条地用汇编语言写出来。这些汇编代码会被汇编器(同样是用汇编或更底层的语言写的)转换成机器码,最终在计算机上运行。这个最初的编译器,它本身就是一个能够理解和处理C语言的程序。

然后,出现了“自举”(Bootstrapping)

一旦有了第一个用汇编语言写的C编译器,事情就开始变得有趣起来。有了这个编译器,我们就可以开始用C语言来写新的C编译器了!

这个过程叫做“自举”。它的逻辑是这样的:

1. 用汇编写一个能编译C的编译器(编译器A)。
2. 用C语言写一个能编译C的编译器(编译器B)。
3. 用编译器A来编译编译器B。 这会生成一个用机器码表示的编译器B。
4. 用这个新生成的编译器B(现在它已经是机器码了)来编译编译器B的C源代码。 如果一切顺利,这将生成一个与之前(用编译器A编译)完全一样的编译器B,但这次是通过C语言工具链产生的。

这个“自举”过程,是许多编译型语言实现自我的关键。通过这个过程,C语言的开发社区就可以不断地改进和优化C编译器,而这些改进都可以通过用C语言本身编写新的编译器来实现,再用这个新编译器去编译旧的编译器,直到最终得到一个高效、可靠的C编译器。

所以,现代的C编译器,绝大多数都是用C语言(或者更高级的语言如C++,或者也有部分用汇编进行优化)写的。 像GCC(GNU Compiler Collection)和Clang这样的知名C编译器,它们的核心部分都是用C或C++编写的。

总结一下这个过程:

最早的C语言编译器: 主要用汇编语言编写。
后续的C语言编译器: 通过“自举”过程,用C语言本身编写,然后用更早期的C编译器编译,最终形成一个完全由C语言工具链生成的编译器。

因此,当我们谈论“C语言本身是用什么语言写的”时,如果指的是最初的实现,那主要是汇编。但如果指的是现在我们使用的绝大多数C编译器,那么它们就是用C语言(或其他高级语言)编写的。这就像一个熟练的工匠,先用基础工具学会了如何制造工具,然后用这些工具制造出更精良的工具,最终让这些工具能够高效地工作。

C语言的这种“自举”能力,是它能够成为一门如此强大且普及的语言的重要原因之一。它提供了一种强大的抽象能力,同时又允许通过底层操作进行极致的优化。这使得C语言在操作系统、嵌入式系统、编译器开发等领域几乎无处不在。

网友意见

user avatar

原回答(21/04/10):

老问题了,新人/非专业人士常常会感兴趣,学过一点编译原理的人都不会问这个问题了。


C语言用什么语言编写?问题的出发点有一些问题,感觉好像一种语言一定要依赖另一种语言一样,其实并不存在这样的依赖链。一种语言编写出来的程序真正依赖的是运行时,和语言本身无关。而尽管很多语言例如java,C#,js都有各自的专属运行时,C语言却没有,他的运行时其实就是——CPU。

换句话说只要有一个东西(不管他是什么),只要能帮我把C语言写成的那段字符串,转换成一个能在CPU上运行的程序,那就够了,我可以不用管这个"东西"是什么。是另一个程序,还是一个人手工翻译然后手动烧录CPU指令;是用C语言写成的程序,还是用JS写成的……我都不用再关心了。

这种转换过程叫编译。如果是一个程序而不是人来做这个步骤,那我们把这样的程序叫做编译器程序。已有的C语言编译器程序,几乎都是用C语言编写的。历史上第一个C语言编译器,自然是用汇编语言来编写[有误]。像我上面说的,能不能用JS编写?理论上当然没问题(比如使用nodejs运行时),只要这个语言本身提供字符串处理,文件处理和二进制处理,就足够了。


然后我用C写好一个文本(字符串),用编译器程序帮我转换成一个可以在CPU上运行的程序,这个程序可不可以也是一个编译器程序呢?自然是没问题的。正因为这样C语言编译器才可能越来越庞大,功能越来越多,支持更复杂的语言特性。历史上正是这么迭代的。


更新(21/04/14):

多谢评论区 @RaySir 提醒"第一个C语言编译器用汇编写"这句话是错的。更多细节请参考评论,我这方面了解的也不是很多。

这个问题居然短暂地上了热搜,怪不得赞的数量蹭蹭蹭往上涨。虽然跟高赞没法比,但已经是我拿到的最高赞的回答了,我一乡下人哪见过这个?(知乎果然是一个流量平台,而不是问答平台[狗头])

我再补充一点,有不少回答提到鸡生蛋。我认为这更像是鸡生鸭蛋,鸭生鹅蛋(新的语言标准迭代)……反过来鹅也能生鸡蛋,鹅也能生鸭蛋,但是没什么意义。问题关键还在于要把三者的本质搞清楚:编译器程序,源代码,编译后的程序。当且仅当编译器和编译后的程序都在同一个运行时环境上,且编译后的程序也是一个同语言的编译器,这才算"自举"。事实上现在的汇编器也是用C写的,因为C语言确实好用啊,但现在的汇编器跟一开始还没有C语言时候的汇编器完全不是同一个东西。

user avatar
  1. 当年KT和DMR应该是用的B语言和汇编写的第一个C编译器。当然有了C之后应该就没什么人再用B语言了。
  2. 后来的C编译器大多是用C写的。其他语言也往往要经历这个过程,叫做自举。
  3. 现在的gcc之类是用C++写的。

Algol60 -> CPL -> BCPL -> B -> C

类似的话题

  • 回答
    这个问题很有意思,也触及到了C语言作为一种基础性语言的根本。很多人听到“C语言本身是用什么写的”时,会先想到“用更高级的语言写的”,比如Python或者Java。但事实并非如此,或者说,这个答案需要更深入的理解。首先,我们需要明确一点:C语言最初的实现,也就是早期的C编译器,并不是用C语言本身写的。.............
  • 回答
    各位老铁们,大家好啊!最近不少朋友咨询我,想找一款靠谱的 C 语言学习编程软件,而且还得是免费的,这可真是说到我心坎里了。毕竟谁不想在学习路上省点钱呢,哈哈!今天我就给大家掏心掏肺地推荐几款,保证都是我亲身用过,觉得好用到爆的!而且我会尽量说得详细点,让大家一看就明白,不像那些冰冰冷冷的 AI 教程.............
  • 回答
    C 语言的设计理念是简洁、高效、接近硬件,而其对数组的设计也遵循了这一理念。从现代编程语言的角度来看,C 语言的数组确实存在一些“不改进”的地方,但这些“不改进”很大程度上是为了保持其核心特性的兼容性和效率。下面我将详细阐述 C 语言为何不“改进”数组,以及这种设计背后的权衡和原因:1. 数组在 C.............
  • 回答
    C 语言王者归来,原因何在?C 语言,这个在编程界已经沉浮数十载的老将,似乎并没有随着时间的推移而消逝,反而以一种“王者归来”的姿态,在许多领域焕发新生。它的生命力如此顽强,甚至在 Python、Java、Go 等语言层出不穷的今天,依然占据着不可动摇的地位。那么,C 语言究竟为何能实现“王者归来”.............
  • 回答
    C语言指针是否难,以及数学大V认为指针比范畴论还难的说法,是一个非常有趣且值得深入探讨的话题。下面我将尽量详细地阐述我的看法。 C语言指针:理解的“门槛”与“终点”首先,我们需要明确“难”的定义。在编程领域,“难”通常指的是: 学习曲线陡峭: 需要花费大量时间和精力去理解和掌握。 容易出错:.............
  • 回答
    C 语言中的 `void main()` 并非是语言标准规定的写法,它的出现和流传,更像是一个历史遗留问题、编译器兼容性以及开发者习惯共同作用的结果。要详细讲解,我们需要从 C 语言的诞生和演变说起。1. C 语言的起源和早期标准 (K&R C) C 语言的诞生: C 语言最初是由 Dennis.............
  • 回答
    C语言自学能到什么高度?详细解析C语言,作为一门强大且经典的编程语言,其学习曲线相对陡峭,但一旦掌握,其应用范围之广,性能之优越,是许多其他语言难以比拟的。 仅凭自学,C语言可以让你达到一个非常高的技术高度,足以让你在许多领域成为一名优秀的开发者甚至专家。以下将从多个维度详细阐述C语言自学所能达到的.............
  • 回答
    在 C 语言中判断一个数列是否为等差数列,核心思想是验证数列中任意相邻两项的差值是否恒定不变。下面我将从概念、算法实现、注意事项以及代码示例等方面进行详细讲解。 一、什么是等差数列?在数学中,等差数列(Arithmetic Progression 或 Arithmetic Sequence)是指一个.............
  • 回答
    在 C 语言中,不用 `goto` 和多处 `return` 进行错误处理,通常依靠以下几种模式和技术。这些方法旨在提高代码的可读性、可维护性,并遵循更结构化的编程原则。核心思想: 将错误处理的逻辑集中到函数退出前的某个点,或者通过特定的返回值来指示错误。 1. 集中错误处理(Single Exit.............
  • 回答
    C 语言中,一些自带函数返回的是指向数组的指针,而你无需手动释放这些内存。这背后涉及到 C 语言的内存管理机制以及函数设计哲学。要弄清楚这个问题,我们需要从几个关键点入手: 1. 返回指针的函数,内存的归属至关重要首先,理解函数返回指针时,内存的“所有权”是谁的,是解决这个疑问的核心。当一个函数返回.............
  • 回答
    在 C 语言中,枚举(`enum`)是一种用户定义的数据类型,它允许你为一组整数常量命名。这使得代码更具可读性和可维护性。而枚举中的 `end` 关键字,严格来说,它本身并不是 C 语言标准枚举定义的一部分,而是一种常见的编程约定或模式,用于标记枚举序列的结束。让我来详细解释一下,并尽可能剥离 AI.............
  • 回答
    在C语言中,严格来说,不能直接“判断”一个变量的类型是否是`int`或`float`。C语言是一种静态类型语言,变量的类型在编译时就已经确定,并且不能在运行时随意更改或检查。当你声明一个变量时,你就已经告诉了编译器它的类型。不过,如果你想表达的是“根据当前存储的值,推断出这个变量应该被视为整数还是浮.............
  • 回答
    在 C 语言中,让不同线程之间能够交流信息、协同工作,这本身就是多线程编程中最核心也是最需要仔细处理的部分。别把它想得太玄乎,无非就是大家共享一块内存,然后约定好怎么读写这块内存罢了。只不过,这“约定”怎么立得住,不让大家互相捣乱,才是关键。咱们把线程通信这事儿,拆解成几个层面来说。 1. 共享内存.............
  • 回答
    在C语言中, `a > b ? a < c ? a : b : c` 这种写法是利用了三元运算符 (?:) 的嵌套。它是一种简洁的条件表达式,用来根据条件的真假返回不同的值。理解它的关键在于一步步拆解它的逻辑。咱们就来好好捋一捋这串表达式的判断过程,讲得透彻一些,保证让你明白它到底是怎么回事儿。首先.............
  • 回答
    C 语言里,一旦你用了 ` ` 来进行换行,确实就“回不去了”——至少在标准的输出流中是这样。这背后的原理,要从计算机如何处理文本输出和终端(或者说显示器)的工作方式说起。核心点:文本流与终端的坐标系统想象一下你的程序输出的文本,就像一条源源不断地向前流动的河流。` `(换行符)就是这条河流中的一个.............
  • 回答
    在C语言中,关于“乘以0.01”和“除以100”哪个更快速,这是一个非常值得探讨的话题,尤其是在追求极致性能的底层开发或者对浮点运算效率敏感的场景下。要回答这个问题,我们需要深入理解计算机如何处理这两种操作,以及它们在硬件层面的具体实现。理解基础:乘法和除法在计算机中的运算首先,我们得明白计算机进行.............
  • 回答
    朋友,咱们这话题聊得挺实在的。C语言现在还有没有“必要”学,未来还有没有“用”,这绝对是个值得深入掰扯掰扯的问题。别听那些虚头巴脑的,咱就从实际出发,好好说说。C语言现在还有没有“必要”学?我想说,如果你想在计算机底层或者和效率打交道,那 C 语言的“必要性”依然挺强的,甚至可以说是基石性的。你得明.............
  • 回答
    在 C 语言编程的世界里,选择一个趁手的编辑器就像是给了你一对飞翔的翅膀。这不仅关乎效率,更影响着你的开发体验和创造力。市面上的编辑器琳琅满目,各有千秋,要说哪个“最好用”,这其实是个非常主观的问题,取决于你的个人习惯、项目需求以及你追求的侧重点。不过,如果你想在众多选择中找到最适合你的那位,不妨先.............
  • 回答
    嘿,哥们,聊到 C 语言的“奇技淫巧”,这可就有意思了。这东西,说白了就是利用 C 语言一些不太直观,但又特别巧妙的特性,来达成一些别人想不到或者达不到的效果。很多时候,这些技巧能让你写出更精炼、更高效的代码,当然了,用不好也容易把自己绕进去。我这里给你掰扯几个比较典型的,保证不像是那种写流水账的A.............
  • 回答
    这个问题在 C 语言中,关于表达式 `a = a++;` 的结果,是初学者乃至一些有经验的程序员都可能感到困惑的地方。它的行为并非我们直观想象的那么简单,并且会涉及到 C 语言中一个非常重要的概念:未定义行为(Undefined Behavior)。首先,让我们尝试理解一下 C 语言是如何处理这个表.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有