平时所说的程序,是指双击后就可以直接运行的程序,这样的程序被称为可执行程序(Executable Program)。在 Windows 下,可执行程序的后缀有.exe
和.com
(其中.exe
比较常见);在类 UNIX 系统(Linux、Mac OS 等)下,可执行程序没有特定的后缀,系统根据文件的头部信息来判断是否是可执行程序。
可执行程序的内部是一系列计算机指令和数据的集合,它们都是二进制形式的,CPU 可以直接识别,毫无障碍;但是对于程序员,它们非常晦涩,难以记忆和使用,例如
puts("VIP会员");
对应的可执行文件二进制写法是
C语言代码由固定的词汇按照固定的格式组织起来,简单直观,程序员容易识别和理解,但是对于CPU,C语言代码就是天书,根本不认识,CPU只认识几百个二进制形式的指令。这就需要一个工具,将C语言代码转换成CPU能够识别的二进制指令,这个工具是一个特殊的软件,叫做编译器(Compiler)。
注意:通常编译后的代码不能直接执行,编译只是把C语言代码转换成机器码,但是还缺少启动代码(startup code)和库代码。
编译器能够识别代码中的词汇、句子以及各种特定的格式,并将他们转换成计算机能够识别的二进制形式,这个过程称为编译(Compile)。
C语言的编译器有很多种,不同的平台下有不同的编译器,例如:
C语言代码经过编译以后,并没有生成最终的可执行文件(.exe 文件),而是生成了一种叫做目标文件(Object File)的中间文件(或者说临时文件)。目标文件也是二进制形式的,它和可执行文件的格式是一样的。对于 Visual C++目标文件的后缀是.obj
;对于 GCC目标文件的后缀是.o
。
为什么不会直接生成可执行文件?因为编译只是将我们自己写的代码变成了二进制形式,它还需要和系统组件(比如标准库、动态链接库等)结合起来,这些组件都是程序运行所必须的。
链接(Link)其实就是一个打包的过程,它将所有二进制形式的目标文件和系统组件组合成一个可执行文件。完成链接的过程也需要一个特殊的软件,叫做链接器(Linker)。
在有些系统中,必须分别运行编译程序和链接程序,而在另一些系统中,编译器会自动启动链接器,用户只需给出编译命令即可。
多个源文件中,编译器每次只能编译一个源文件,生成一个目标文件,这个时候,链接器除了将目标文件和系统组件组合起来,还需要将编译器生成的多个目标文件组合起来。
编译是针对一个源文件的,有多少个源文件就需要编译多少次,就会生成多少个目标文件。
以前,UNIX C编译器要调用语言定义的cc
命令。但是,它没有跟上标准发展的脚步,已经退出了历史舞台。但是,UNIX 系统提供的C编译器通常来自一些其他源,然后以cc命令作为编译器的别名。
对于当前主流桌面操作系统而言,可使用 Visual C++(MSVC、VC)、GCC以及 LLVM Clang 这三大编译器。
Visual C++(简称 MSVC)是由微软开发的,只能用于 Windows 操作系统,它不开源。用户可以使用 Visual Studio Community 版本来免费使用它,但是如果要把通过 Visual Studio Community 工具生成出来的应用进行商用,那么就得好好阅读一下微软的许可证和说明书了。而使用 GCC 与 Clang 编译器构建出来的应用一般没有任何限制,程序员可以将应用程序随意发布和进行商用。
GNU 项目始于1987 年,是一个开发大量自由UNIX 软件的集合(GNU 的意思是GNU ’s Not UNIX,即GNU 不是UNIX )。GNU 编译器集合(也被称为GCC ,其中包含GCC C编译器)是该项目的产品之一。GCC 在一个指导委员会的带领下,持续不断地开发,它的C编译器紧跟C标准的改动。GCC 有各种版本以适应不同的硬件平台和操作系统,包括UNIX 、Linux 和Windows 。用gcc
命令便可调用GCC C编译器。许多使用gcc 的系统都用cc
作为gcc
的别名。
LLVM 项目成为cc的另一个替代品。该项目是与编译器相关的开源软件集合,始于伊利诺伊大学2000 年的研究项目。它的Clang编译器处理C代码,可以通过clang
调用。有多种版本供不同的平台使用,包括Linux。2012 年,Clang 成为FreeBSD 的默认C编译器。Clang 也对最新的C标准支持得很好。
而在嵌入式系统方面,可用的C语言编译器就非常丰富了,比如:
通常,用于嵌入式系统开发的编译工具链都没有免费版本,而且一般需要通过国内代理进行购买。所以,这对于个人开发者或者嵌入式系统爱好者而言是一道不低的门槛。
不过 Arduino 的开发套件是可免费下载使用的,并且用它做开发板连接调试也十分简单。Arduino 所采用的C编译器是基于 GCC 的。
还有像树莓派(Raspberry Pi)这种迷你电脑可以直接使用 GCC 和 Clang 编译器。此外,还有像 nVidia 公司推出的 Jetson TK 系列开发板也可直接使用 GCC 和 Clang 编译器。树莓派与 Jetson TK 都默认安装了 Linux 操作系统。
在嵌入式领域,一般比较低端的单片机,比如 8 位的 MCU 所对应的C编译器可能只支持 C90 标准,有些甚至连 C90 标准的很多特性都不支持。因为它们一方面内存小,ROM 的容量也小;另一方面,本身处理器机能就十分有限,有些甚至无法支持函数指针,因为处理器本身不包含通过寄存器做间接过程调用的指令。
而像 32 位处理器或 DSP,一般都至少能支持 C99 标准,它们本身的性能也十分强大。而像 ARM 出的 RVDS 编译器甚至可用 GNU 语法扩展。