如何编译和运行C++程序?
C语言编译和链接详解

可执行程序

我们平时所说的程序,是指双击后就可以直接运行的程序,这样的程序被称为可执行程序(Executable Program)。
在 Windows 下,可执行程序的后缀有 .exe 和 .com(其中 .exe 比较常见);
在类 UNIX 系统(Linux、Mac OS 等)下,可执行程序没有特定的后缀,系统根据文件的头部信息来判断是否是可执行程序。

编译

可执行程序的内部是一系列计算机指令和数据的集合,它们都是二进制形式的,CPU 可以直接识别,毫无障碍;但是对于程序员,它们非常晦涩,难以记忆和使用。
C语言代码由固定的词汇按照固定的格式组织起来,简单直观,程序员容易识别和理解。
但是对于CPU,C语言代码就是天书,根本不认识,CPU只认识几百个二进制形式的指令。
这就需要一个工具,将C语言代码转换成CPU能够识别的二进制指令,也就是将代码加工成 .exe 程序;这个工具是一个特殊的软件,叫做编译器(Compiler)。
编译也可以理解为“翻译”,类似于将中文翻译成英文、将英文翻译成象形文字。
它是一个复杂的过程,大致包括词法分析、语法分析、语义分析、性能优化、生成可执行文件五个步骤,期间涉及到复杂的算法和硬件架构。

链接

C语言代码经过编译以后,并没有生成最终的可执行文件(.exe 文件),而是生成了一种叫做目标文件(Object File)的中间文件(或者说临时文件)。目标文件也是二进制形式的,它和可执行文件的格式是一样的。
对于 Visual C++,目标文件的后缀是.obj;对于 GCC,目标文件的后缀是.o。

目标文件经过链接(Link)以后才能变成可执行文件。既然目标文件和可执行文件的格式是一样的,为什么还要再链接一次呢,直接作为可执行文件不行吗?

不行的!因为编译只是将我们自己写的代码变成了二进制形式,它还需要和系统组件(比如标准库、动态链接库等)结合起来,这些组件都是程序运行所必须的。

链接(Link)其实就是一个“打包”的过程,它将所有二进制形式的目标文件系统组件组合成一个可执行文件。完成链接的过程也需要一个特殊的软件,叫做链接器(Linker)。

随着我们编写的代码越来越多,最终需要将它们分散到多个源文件中,编译器每次只能编译一个源文件,生成一个目标文件,这个时候,链接器除了将目标文件和系统组件组合起来,还需要将编译器生成的多个目标文件组合起来。
再次强调,编译是针对一个源文件的,有多少个源文件就需要编译多少次,就会生成多少个目标文件。
这个文章里讲了目标文件、可执行文件内部的结构。还介绍了“符号表”的概念,以及链接的具体过程。

编译器

如果不是特别强调,一般情况下我们所说的“编译器”实际上也包括了链接器。
C语言的编译器有很多种,不同的平台下有不同的编译器,例如:

  • Windows 下常用的是微软编译器(cl.exr),它被集成在 Visual Studio 或 Visual C++ 中,一般不单独使用;
  • Linux 下常用的是 GUN 组织开发的 GCC,很多 Linux 发行版都自带 GCC;
  • Mac 下常用的是 LLVM/Clang,它被集成在 Xcode 中(Xcode 以前集成的是 GCC,后来由于 GCC 的不配合才改为 LLVM/Clang,LLVM/Clang 的性能比 GCC 更加强大)。

    集成开发环境

    实际开发中,除了编译器是必须的工具,我们往往还需要很多其他辅助软件,例如:

  • 编辑器:用来编写代码,并且给代码着色,以方便阅读;

  • 代码提示器:输入部分代码,即可提示全部代码,加速代码的编写过程;
  • 调试器:观察程序的每一个运行步骤,发现程序的逻辑错误;
  • 项目管理工具:对程序涉及到的所有资源进行管理,包括源文件、图片、视频、第三方库等;
  • 漂亮的界面:各种按钮、面板、菜单、窗口等控件整齐排布,操作更方便。


这些工具通常被打包在一起,统一发布和安装,例如 Visual Studio、Dev C++、Xcode、Visual C++ 6.0、C-Free、Code::Blocks 等,它们统称为集成开发环境(IDE,Integrated Development Environment)。

C++程序运行过程

C++ 和C语言类似,也要经过编译和链接后才能运行。
VS、Dev C++、VC 6.0、Code::Blocks、C-Free、GCC、Xcode 等常见 IDE 或编译器,它们除了可以运行C语言程序,还可以运行 C++ 程序。
下图是 C/C++ 代码生成可执行文件的过程:
编译、链接、运行 - 图1
C语言源文件的后缀非常统一,在不同的编译器下都是.c。C++ 源文件的后缀则有些混乱,不同的编译器支持不同的后缀,下表是一个简单的汇总:

编译器 Microsoft Visual C++ GCC(GNU C++) Borland C++ UNIX
后缀 cpp、cxx、cc cpp、cxx、cc、c++、C cpp C、cc、cxx