每种语言都是用C编写的吗?


180

有时,当使用不同的语言(C / C ++,C#)进行编程时,我想到了这种想法:

  • 每种语言都用C编程语言编写吗?
  • C语言是所有语言的母亲/父亲吗?
  • 每个概念(OOP等)是否都在C中实现?

我的方向正确吗?


58
@XLAnt:许多(也许甚至大多数)C编译器都是用C编写的。
JörgW Mittag 2014年

32
@Neil:C ++不能编译为任何东西。C ++是一种语言。语言不编译,编译器编译。
约尔格W¯¯米塔格

12
@XLAnt:我不这么认为。但是,例如,第一个Oberon编译器是用Oberon编写的,然后手动翻译(我猜是编译的一种形式)到Fortran。然后使用Fortran编译器对该编译器进行编译,然后使用生成的Oberon编译器来编译Oberon编译器,从那时起,将使用编译器的先前版本来编译下一个编译器。
约尔格W¯¯米塔格

18
@Neil真的不是那么学究。没错:语言是一种规范。它可以实现为编译器,解释器,混合器等。您可以某种语言编写编译器,但编译器不是该语言。我猜这个问题会令人困惑,因为除了参考实现之外,在任何地方都没有针对任何语言编写规范的语言。但是即使在那种情况下,我也会认为语言(即作者心目中的理想语言)与实现/编译器/解释器/等不同。
Andres F.

21
唐纳德:这是一个很合理的问题,答案很明确。答案是否定的,没有理由不赞成。相反,请考虑回答和解释。
Andres F.

Answers:


207

没有。

OCaml,Haskell,Lisp方言(例如Scheme)和其他几种语言经常被用于开发爱好语言。

许多语言都是用C语言实现的,因为它是一种普遍存在的语言,而诸如lexer-parser生成器(例如yacc和bison)之类的编译器编写工具则易于理解,并且几乎无处不在。

但是C本身在最初创建时最初不能用C开发。实际上,它最初是使用B语言开发的。较早的语言(如Fortran)通常使用本机汇编语言甚至机器代码来引导,远早于C出现。

无关地,像OOP这样的语言范例通常与语言无关。例如,功能范式(由Alonzo Church创立)早在任何编程语言都存在之前就已作为数学基础。过程化和结构化的编程范式来自于像约翰·冯·诺依曼这样的理论家的数学著作。面向对象是由几项不同且无关的工作开发的,其中一些来自lambda演算(功能范式),一些则来自于动态编程系统,例如Alan Kay在Xerox PARC的SmallTalk。

在这些想法产生数十年后,C只是故事的一小部分。


40
虽然确实很明显第一个C编译器显然不能用C编写,但现在肯定有可能。
reirab 2014年

17
@reirab更多钞票真。GCC用C编写,通常使用GCC进行编译
Darkhogg 2014年

9
当然,GCC现在正在改写C ++,但是这不是一个事实,即第一个C编译器不能用C语言来写为重要
greyfade

10
@greyfade gcc已经有一段时间没有C了。它不是“现在正在被重写”,而是“已经用C ++编写了两年以上”(尽管它比这更旧,那是当合并发生时才将其移至C ++)。

13
@greyfade不是“ C,而是具有C ++功能”,不是C ++的定义吗?
KutuluMike 2014年

91

每种语言都用C语言编写吗?

语言是一组抽象的数学规则和限制(“如果我写这个就会发生”)。确实没有写任何东西。

它通常是由形式化的英语子集,数学符号以及某些特殊的规范语言混合而成的。该语法通常在EBNFABNF的变体中指定。

例如,以下是forISO Ruby语言规范中表达式的规范:

§11.5.2.3.4 for表达式

句法

  • for表达式 for 变量 [此处没有行终止符] in 表达式 子句 end
  • 变量 左手边 | 多个左手边

语义学

用于表达如下评价:

  1. 计算表达式。如果对表达式的求值由break-expressionnext-expressionredo-expression终止,则行为不确定。否则,将O其作为结果值。
  2. E初级方法调用形式的基本表达式 [无线-终止这里] .each do | 块参数列表 | 块体 end,其中所述的值基本表达式O,该块参数列表换变量,该块体是所述化合物语句的的do-子句

    评估E; 然而,如果一个块,其块体是所述化合物语句的的do-子句用于表达该评价过程中被调用时,在除了步骤c§11.3.3以下步骤a)和步骤e)4)应用于评估此通话。

  3. 所述的值对于表达是所得到的调用的值。

这是与Scala的类型一致性规则不同的示例:

多态型[A 1 >:L 1 <:U 1,...,A Ñ >:L Ñ <:U Ñ ] T,符合多态型[A1>:L' 1 <:U' 1,...,一个ñ >:L' ñ <:U' ñ ] T'如果,假定L' 1 <:一个1 <:U' 1,...,L' ñ <:一个ñ <:U'n之一具有Ť<:T '大号 <:L' U' <:U i for i∈{1,…,n}


C语言是所有语言的母亲/父亲吗?

不它不是。C还很年轻。有很多古老的语言。由于时间旅行实际上是不可能的,因此C根本不可能对那些旧语言产生任何影响。

  • 普兰卡库(1943)
  • 速度编码(1953)
  • 福尔特拉(1954)
  • IPL(1956)
  • Lisp(1958)
  • 阿尔高(1958)
  • 科伯(1959)
  • 欢乐(1960)
  • APL(1962)
  • 西姆拉(1962)
  • 斯诺博(1962)
  • CPL(1963)
  • 基本(1964)
  • PL / I(1964)
  • 角色扮演(1964)
  • BCPL(1966)
  • ISWIM(1966)
  • MUMPS(1967)
  • 福斯(1968)
  • LOGO(1968)
  • 复仇(1968)
  • B(1969)
  • 极乐(1970)
  • 帕斯卡(1971)
  • KRL(1971)
  • 小话(1972)

所有这些在C发明之前就已经存在。即使在C存在之后,许多其他对象也没有C的影响。PASCAL语言家族(ALGOL-58,ALGOL-60,ALGOL-X,ALGOL-W,PASCAL,Modula-2,Oberon,Oberon-2,Active Oberon,Component Pascal)是完全独立的谱系。整个Lisp系列(LISP,Franz Lisp,InterLisp,MacLisp,Scheme,Flavours,LOOPS,CommonLoops,Dylan,CommonLisp,Arc,Clojure,Racket等)也不相关。函数语言(ISWIM,KRL,Miranda,ML,SML,CAML,OCaml,F#,Haskell,Gofer,Clean)和整个依存类型家族(Agda,Coq,GURU,Idris)都离C尽可能远。对于Smalltalk系列(Smalltalk,Self,Newspeak,Us,Korz),逻辑编程系列(PLANNER,Prolog,Mercury),SQL以及许多其他产品也是如此。

每个概念(OOP等)都用C语言实现吗?

具有OO概念的第一语言是Simula(1960)和Smalltalk(1972),但是面向对象的系统早在1953年就已构建(没有将其称为)。再一次,这比C早就存在了,所以OO不可能与C有任何关系。



2
@leftaroundabout:那是一个很棒的博客文章,这是我多年来的最爱之一。
约尔格W¯¯米塔格

1
@FrancisDavey:谢谢。我开始从内存中编译列表,然后通过在Wikipedia上查找它们添加了我不记得的日期。之后,我在Wikipedia上找到了语言的时间表,并从中选择了更多的语言。由于有关BCPL的文章引用了1966,但时间轴引用了1967,所以我没有注意到我已经添加了BCPL。我将删除重复项。
约尔格W¯¯米塔格

1
在您的列表中,“ htroF”不是反拼吗?
chux

2
“时间旅行实际上是不可能的” –这是一个极具争议的主张。当然不会减损此答案的价值。
康拉德·鲁道夫

50

许多重要语言的大多数核心都是用C编写的,但是情况正在发生变化:

  • Python(CPython)的参考实现是用C编写的(但是还有其他用其他语言编写的实现,例如Jython / Java,PyPy / Python,IronPython / C#...)
  • PHP Zend Engine用C编写
  • Sun Microsystems开发的第一个Java编译器最早是用C编写的,但是现在类库始终是用Java编写的(因为它们打算使用Java VM本身运行)。某些使用JNI(Java本机接口)的库可能会用多种其他语言部分编写,因为它们打算在JVM之外使用。

    Sun / Oracle VM用C ++编写。BEA / Weblogic / Oracle VM用C编写。但是有JVM用Java,Lisp,SmallTalk(IBM)编写...

  • Perl被实现为用C编写的核心解释器,以及大量用Perl和C编写的模块集合(但是Pugs是Perl 6编程语言的编译器和解释器,是用Haskell编写的)。
  • 正式的Ruby解释器(通常称为Matz的Ruby解释器或MRI)是用C语言编写的,并且使用自己的Ruby专用虚拟机(但是有JRuby是在Java虚拟机上运行的Java实现; Rubinius是C ++使用LLVM在运行时编译为机器代码的字节码虚拟机...)
  • R的大约50%用C编写
  • 当然,C是用C编写的!(但是第一个针对PDP-11的C编译器是B和汇编器的组合)。

经常选择C的原因有很多:性能,可移植性,经验。

最后一个可能是最重要的:Python于1991年启动,PHP于1994/1995年启动,Perl于1988年启动,Ruby于1995年启动。在那些年中,Java刚刚发布,而C ++尚未很好地标准化。


有点相关:


5
从编译器/解释器的实现角度来看,C已经/是一个参考点。另外,它直接或间接地影响了许多后来的语言(至少在语法上)。
manlio 2014年

2
很快,您就可以说C#是用C#编写的!(种类)
DLeh 2014年

1
大多数Mono(包括C#编译器和许多/大部分.NET基类库)都是用C#编写的。
查理·基利安

3
问题答案“ C是所有语言的父母吗?” 是“否”,因此我认为提供很多用C编写的示例无济于事。反例会有所帮助,但是您的选择仍然是C 派生的。例如,即使Java,Python等。现在是自托管的,它们仍然是从C启动的,因此它们就像C的“孙子代”。LISP,FORTRAN,ML和(当然)机器代码之类的语言是真正的反例,因为C从未参与他们的创造。
Warbo,2014年

2
当然,要尽可能多地实现许多语言的愿望。但是,似乎大多数语言都依赖C,因为大多数语言都需要能够调用C才有用。大多数现代操作系统API和有用的库都倾向于具有C绑定。您还必须注意“写入”的含义。语言实现通常包含多个部分:至少是编译器和运行时系统。运行时系统通常用C编写,以更好地与OS交互。
别名2014年

10

不,某些语言早于C。许多语言独立于C实现,例如,请参见http://en.wikipedia.org/wiki/Lisp_%28programming_language%29


2
Java有许多实现,大多数是用Java编写的。Objective-C的GNU实现是用C编写的(或者,我相信C ++最近有所更改),LLVM实现是用C ++编写的,并且曾经有一个用C#编写的解释器。Python有很多实现,一种是用RPython编写的,一种是用Java编写的,一种是C#编写的,一种是C编写的。PHP有六个主要实现,两种是用Java编写的,两种是C#编写的,一种是C编写的,一种是用C ++编写的。
约尔格W¯¯米塔格

1
不会。语言设计师当然会受到其他语言的影响,但如果愿意,他们可以选择忽略这些影响。
约尔格W¯¯米塔格

2
@FaizanRabbani语言从本质上讲是范式,模式和折衷的概念和选择-通常情况下,“一种语言是从其他语言创建/改编的”,但这与编译器的实现语言完全无关;语言X可以从语言Y派生而来,但可以用C或其他完全实现的语言实现-通常就是这种情况。在这种情况下,“概念祖先”很重要,但是编译器语言只是勉强相关的技术细微差别,可以随着时间的流逝而变化。
Peteris 2014年

3
最后一个链接是否具有可疑的价值-其中有太多错误,无法真正加以重视。
未知编码者2014年

4
@SebastianGodelet:HotSpot不是Java语言的实现。它是JVM字节码语言的实现。那是两种完全不同的语言。Java语言使用最广泛的实现javac来自于Martin Odersky(由Scala出名)以100%Java编写的Oracle JDK / OpenJDK,以100%Java编写的Eclipse编译器(源自IBM的Jikes编译器),来自IBM的J9,也源自Jikes和100%Java。AFAIK是GCJ
–JörgW Mittag 2014年

4

如果可以的话,我会发表评论,但我不能这样说:

C如此普遍存在的原因之一是因为它是最早开发的语言之一,并且大量现代语言都基于其结构(Java,Go,PHP,Perl等)-使其看起来像更多的地方。

另一个经常被遗忘的原因是1973年Unix用C重写,并且Unix的许多系统调用也可以作为C程序/函数使用,从而使两者高度互连。由于Unix是整个现代编程发展的重要组成部分,因此C被拖入了臭名昭著的行列。

说了这么多,您的问题的答案是“否”。C语言基于一种称为ALGOL的语言,并且有很多竞争对手都使用ALGOL(FORTRAN,Lisp,COBOL)和C(没人想到)。面向对象的编程,可以说是编程设计中最大的范式转变,并不是源于C的-尽管C ++是一种非常流行的OOP语言(它首先出现在Lisp或Simula 67中,具体取决于您问的是谁)。到OOP出现时,C已经成为一种流行的语言,因此它不必成为第一门语言-它是如此流行,以至于C ++的“扩展”可以说也成为主要的OOP语言之一。它由于其强大的内存控制功能(您可以直接分配和取消分配您的结构创建的内存)而仍在现代使用,允许它在紧缩的内存预算(例如视频游戏)及其高度优化的编译器(显然取决于编译器)上创建程序。诚然,随着Java JIT编译和语言存储管理器变得更加先进,即使这些功能也正在逐渐失去优势。


1
这似乎并没有提供任何关于先前答案中提出和解释的要点的实质内容,特别是在前一个答案中,除非有可疑的说法,即“ C基于一种称为ALGOL的语言”
gnat 2014年


实际的故事是比这更复杂和有趣; 我想说的是,这里的布局方式对读者几乎无济于事
gnat 2014年

3

显然不是。如果以前不存在C,如何用C编写第一个C编译器?这不是鸡和蛋的问题。

有很多方法可以编写一种语言的第一个编译器,称为引导程序

而且,大多数编译器都试图实现自我托管,或者以其语言对其自身进行编译,主要是为了促进语言和编译器本身的发展。


12
第一个Oberon编译器用Oberon编写的。如果您是一名教授,并且有很多学生可以为您手动翻译编译器(Wirth教授有),那很好。
约尔格W¯¯米塔格

上面链接的引导文章中提到的@Jorg,所以我不必理会,因为这个问题是关于C的,并且没有以这种方式编写C编译器
phuclv 2014年

14
@JörgWMittag-第一个自动化的 Oberon编译器是用Oberon编写的。真正的第一个 Oberon编译器是一群学生。
nnnnnn 2014年

4
@nnnnnn:我会认为这“一群学生”是解释器,而不是编译器。
圣保罗Ebermann

4
@PaŭloEbermann要添加另一个人为元素:“计算机”最初是一个职称
chux 2015年

2

这是一些不是用C编写的编程语言的列表,以及它们哪种语言实现的列表:

  • Haskell-Haskell
  • 伊德里斯-哈斯克尔
  • 阿德加-哈斯克尔
  • 冲突-哈斯克尔
  • PureScript-Haskell
  • 榆木-哈斯克尔
  • 水星-水星
  • 锈-锈(最初为OCaml)
  • 去-去
  • 水晶-水晶
  • OCaml-OCaml
  • 弗雷格-弗雷格+ Java
  • Haxe-OCaml + Haxe
  • Scala-Scala
  • Futhark-哈斯克尔
  • ATS-ATS

实现编译器的最佳语言可能与C相去甚远。功能语言为您提供了诸如递归方案和monadic解析器组合器之类的功能(前提是您拥有类型类),这使它们特别适合于编译器工作。

其次,要解决您的问题,即C是否是“所有编程语言的母子”?C在出现时是一种设计良好的语言,毫无疑问,它影响了语言设计者,他们后来继续做非常不同的事情。但是,归根结底,Haskell基本上以各种可能的方式离开了C。C已有45岁,并且在此期间我们学会了做得更好,这并不奇怪。

最后,要回答您的第三个问题,根本不是C实现“所有概念”。特别是,尝试用C来实现功能编程中的一些高级概念(例如变质,或者,上帝禁止,同步同构)会非常困难。我对面向对象的编程不是特别熟悉,但是我确实知道某些面向对象的语言具有求和类型。


C从来不是“一种设计得令人难以置信的语言”。我们今天看到的疣从一开始就是众所周知的疣。但是,它足以成为易于开发人员使用的Unix操作系统的本地语言,在Bell Labs将Unix推入大学之后,C / Unix成为了一代计算机专业人员最喜欢的语言/ OS。
所罗门慢

PS。,在C中没有很多原始想法。如果您正在寻找所有块结构化,程序化编程语言的母亲/父亲,您可能想看看ALGOL
所罗门慢

Lisp宏比C更好,并且ALGOL和Smalltalk具有块,闭包和嵌套函数来帮助组织代码。实际上,Lisp可以用作汇编程序的宏处理器,并且创建的代码比早期C. Simula(在C具有多态性之前出现)更短,更快(自定义S表达式的处理)。Lisp,APL和Smalltalk的“ shell”具有完全的功能(shell和程序之间的代码相同),而与Unix的“ sh”和“ C”不同,允许解释和编译的代码相互交错。指针在Lisp(rplaca / rplacd)中更容易。
aoeu256

C的最大优点是为C构建“编译器”更加容易,因此它可以更容易地传播……就像病毒一样,而且由于C,现代程序员对如何构建模块化程序毫无头绪。 (可变性会损害模块性),没有副词/组合器/高阶函数的概念[每次都手动编写循环],并且我们的CPU受“冯·诺依曼”瓶颈的限制,因为我们的操作系统是用C编写的,因此我们需要CPU运行C代码以实现向后兼容性。
aoeu256

1

编程语言是规范(不是软件!),通常用一些英文文档编写(带有某种形式化,例如,大多数语法的EBNF;有时它们的语义也被部分形式化)。

例如,C11由n1570定义(您应该阅读)。Scheme的某些方言由R5RS定义(您也应该阅读,它写得很好)。

编程语言可以通过某些软件来实现。有时,该软件是用编程语言本身编写的编译器。阅读有关引导编译器的信息

可以使用已编译的编程语言本身编写编译器。如果该语言XX是全新的,则需要经过一个临时步骤,该步骤涉及使用某种其他实现语言(也许是C)编写该语言的子集的最小解释器或编译器,之后您可以丢弃该临时编译器或解释器(不必足够好即可编译其他编译器)。一旦编译了用XX编写的XX编译器,就可以丢弃临时编译器。

通常(但并非总是),运行时系统部分用C(特别是垃圾收集器)编写。

请注意,骨头是一个完全由其自身编写的Scheme编译器和运行时(您可以找到完全自举实现的许多其他示例)。

顺便说一句,使用C作为编译器目标语言很方便。

如今,许多编程语言实现都是免费软件开源的。随时学习(或为它们的源代码做贡献)!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.