原文:C track: compiling C programs.

C track: compiling C programs.


尽管有些计算机语言(如 Schema 或者 Basic)通常使用交互式的解释器(当你输入命令后,就可立即执行),但 C 语言不是。C 的源文件总是要通过一个叫做编译器(compiler)的程序编译成二进制代码然后运行。这就是我们接下来要详细说明的几个步骤。


几种不同类型的文件

你需要4种文件进行编译C 程序:

  1. 常规的源代码文件(source code)。 这些文件包含了函数定义,并约定以 ".c" 作为结尾进行命名。

  2. 头文件(Header). 这些文件包含了函数声明(也叫做函数原型)以及各种预处理语句。源文件可以通过头文件访问外部定义的函数。头文件的文件名约定以 ".h" 作为结尾.

  3. 目标文件(Object). 这些文件由编译器的输出而产生。目标文件包含了二进制形式的函数定义,本身是不可执行文件。目标文件的文件名约定以".o" 结尾,尽管在一些操作系统,如(Windows, MS-DOS),经常以".obj" 结尾。

  4. 二进制可执行文件(Binary executables)。这些文件由一个叫做链接器(linker)的程序的输出而产生。链接器链接一些目标文件并产生可以直接执行的二进制文件。二进制可执行文件在 Unix 操作系统上没有后缀名,但在 Windows 上,通常以".exe" 作为后缀名。

还有其他的各种文件,尤其是静态库文件(".a" files or ".lib" on Windows)以及共享库文件(".so" files or ".dll" on Windows)。但通常,你不需要直接与他们打交道。

预处理

在编译器开始编译源文件之前,源文件由预处理器(preprocessor)进行处理。预处理器是一个真实的单独的程序(通常叫做"cpp", for "C preprocessor"),而由编译器在编译前自动调用。预处理器的工作就是讲源文件转换成另外一个源文件(你也可以认为是对源文件的修改或者扩展)。修改后的文件可能作为一个真实的文件存在文件系统中,也可能仅仅是在发送给编译器之前在内存中作短暂的保留。另外,你不需要特别关注预处理,但是你需要知道预处理是干什么滴。

预处理指令以符号("#")开始. 在多种预处理指令中,有两种最为重要:

  1. #define. 主要用于定义常量。如,

        #define BIGNUM 1000000
    

    指定在剩下的程序中任何位置处理的字符串 BIGNUM 应该被替换为 1000000。例如,这个语句:

        int a = BIGNUM;
    

    变成了

        int a = 1000000;
    

    #define 语句用于避免一个常量值在源文件中多处重复出现。这在你随后需要对这常量值进行修改时是相当的重要,并且可以减少bug 的滋生,你只需要对 #define 的定义修改,而不是对常量值在整个源代码中多处的出现位置进行修改。

  2. #include. 用于访问位于源文件之外的函数定义。例如:

        #include <stdio.h>
    

    在源代码编译之前,预处理器将<stdio.h> 的内容替换 #include 语句所在的位置。 #include 总是用于主要包含函数声明和#define 语句的头文件。 这时,我们可以通过 #include 语句而使用一些函数,如 printf 和 scanf, 这两个函数的声明就位于文件 stdio.h 中. 在源文件中,在函数声明或者定义之前,C compilers 是不允许我们使用函数的;#include 语句就是用于这种情况,从而使我们可以复用之前用C 编写的代码。

还有其他的各种预处理指令,我们将会根据需要进行有所处理。

生成目标文件: 编译器

在 C 预处理器包含了所有的头文件并且展开所有的 #define 和 #include 语句(也有其他一些在源文件中出现的预处理指令)后,编译器就可以编译程序了。编译器将 C 源文件编译成目标文件(object code),包含二进制版本源代码并以 ".o" 结尾的文件。 然而,目标文件并不能直接运行。为了能够生成可执行文件,你还需要加入被#included 包含的库函数代码(这个通过 #include 包含函数声明是不一样的)。这就是下一节要讲到的链接器 linker 的工作。

通常,编译由以下方式被调用:

    % gcc -c foo.c

符号 % 是 unix 提示符. 它告诉编译器对文件 foo.c 运行预处理程序并编译成目标文件 foo.o。 -c 选项意思是由编译器将源文件编译成目标文件而不会调用链接器。如果你的整个程序就一个源文件,你也可以这么做:

    % gcc foo.c -o foo

它告诉编译器在文件 foo.c 运行预处理器,编译并链接产生一个可执行文件 foo。-o 表示二进制可执行文件(程序)将以其随后的单词作为文件名。 如果你不制定 -o 选项,或者仅仅是输入 gcc foo.c,由于某种历史原因,可执行文件将以 a.out 命名。

请注意编译器的名字,我们使用的是 gcc,代表 "GNU C compiler" 或者 "GNU compiler collection" 。也有其他的编译器;他们中大多数都以 cc("C compiler")命名。在 Linux 操作系统中 cc 是 gcc 的别名。

揉成一团: 链接器

链接器的工作就是将一组目标文件(.o 文件)一起链接到一个二进制可执行文件。这包括从你的源代码文件编译的目标文件,以及预编译的库文件(library files)。 这些文件 .a 或者 .so 作为结尾命名,通常你不需要知道他们,因为他们中大多数可以由链接器(linker)定位并根据需要自动链接。

像预处理器一样,链接器也是一个叫做 ld 独立的程序。也如预处理器一样,链接器在你使用编译器时自动被调用。链接器通常使用的方式如下:

    % gcc foo.o bar.o baz.o -o myprog

这一行是告诉编译器一起将三个目标文件(foo.obar.o, and baz.o) 链接成一个名为 myprog 的二进制可执行文件.

这就是你需要知道如何编译你的 C 程序的事情。通常,我们也推荐 -Wall 选项:

    % gcc -Wall -c foo.cc

-Wall 选项让编译器对合法但是可以的代码结构发出警告,并且帮助你轻松捕获一些 bugs。如果你想要更多的编译检查项:

    % gcc -Wall -Wstrict-prototypes -ansi -pedantic -c foo.cc

-Wstrict-prototypes 选项是让编译器对代码中没有正确原型的函数做出警告。-ansi 和 -pedantic 是让编译器对代码中不可移植的结构(e.g. 一些在 gcc 中合法而不满足标准 C compilers 的代码结构;这些结构通常是需要避免的)做出警告。


References

  • Kernighan and Ritchie, The C Programming Language, 2nd Ed.

  • The man page for gcc. Type:  man gcc   at the unix prompt.

  • The GNU Info documentation on gcc.  Warning! This is far more information than most people could possibly absorb in the average millenium.

    Info documentation on gcc can be accessed through the GNU emacs editor by typing "M-x info" (where "M-x" means to hit the meta-key and "x" simultaneously), or "C-h i" (where "C-h" means to hit the control key and "i" simultaneously), followed by "mgcc<return>". Type "minfo<return>" instead for a quick tour of how to use info. You can also access the info documentation from the unix command line by typing  info gcc.


[译] C track: compiling C programs.的更多相关文章

  1. Linux内核Makefile文件(翻译自内核手册)

    --译自Linux3.9.5 Kernel Makefiles(内核目录documention/kbuild/makefiles.txt) kbuild(kernel build) 内核编译器 Thi ...

  2. Beginning Scala study note(1) Geting Started with Scala

    1. Scala is a contraction of "scalable" and "language". It's a fusion of objecte ...

  3. linux内核的makefile.txt讲解

    linux内核的linux-3.6.5\Documentation\kbuild\makefiles.txt Linux Kernel Makefiles This document describe ...

  4. CUDA1-hello world

    电脑配置:windows7 sp1 64bit  + CUDA6.5 + GeForce GTX780 Ti 显卡中的GPU因为多核可以处理很多相同的操作,相比较来说cpu就像个健全的手,什么活都能干 ...

  5. 安装coreseek找不到mysql

    1.安装 coreseek-3.2.14 遇到问题:“ERROR: cannot find MySQL include files,随即在网上搜索各种答案说是要找到mysql.h的正确路径加入./co ...

  6. OpenMP for Fortran

    OpenMP for Fortran OpenMP Directive Syntax of OpenMP compiler directive for Fortran: !$OMP Directive ...

  7. mysql 升级方法

    Performing an In-place Upgrade This section describes how to perform an in-place upgrade. Review Bef ...

  8. 《 UNIX网络编程》源码的使用

    学习编程这东西,看代码,改代码,运行代码这样才能学到实际东西!本书说在www.unpbook.com可以获取源码,不过打不开!所以google unpv13e.tar.gz 并在网络上找到了:源码:h ...

  9. 嵌入式Linux-GNU Make 使用手册(中译版)

    GNU Make 使用手册(中译版) 翻译:于凤昌 译者注:本人在阅读Linux源代码过程中发现如果要全面了解Linux的结构.理解Linux的编程总体设计及思想必须首先全部读通Linux源代码中各级 ...

随机推荐

  1. LeetCode126:Word Ladder

    题目: Given two words (start and end), and a dictionary, find the length of shortest transformation se ...

  2. Retention、Documented、Inherited三种注解

    Retention注解 Retention(保留)注解说明,这种类型的注解会被保留到那个阶段. 有三个值:1.RetentionPolicy.SOURCE —— 这种类型的Annotations只在源 ...

  3. js限制input输入

    1.取消按钮按下时的虚线框,在input里添加属性值 hideFocus 或者 HideFocus=true <input type="submit" value=" ...

  4. R 网页数据爬虫1

    For collecting and analyzing data. [启示]本处所分享的内容均是笔者从一些专业书籍中学习所得,也许会有一些自己使用过程中的技巧.心得.小经验一类的,但远比不上书中所讲 ...

  5. 环境搭建二 secureCRT配置

    上一篇里面讲到了虚拟机安装,以及secureCRT的远程连接.此篇文章介绍secureCRT的配置. 颜色设置 参考   http://jingyan.baidu.com/article/a681b0 ...

  6. j2ee log4j集中式日志解决方案logpool v0.3

    V0.3相对于v0.2的更新如下:

  7. linux环形buff模拟多线程信号量操作

    互斥锁mutex变量的值非0即1,只能用来表示两种状态下的临界资源.而信号量是与之类似的,用来表示可用资源的,区别在于,信号量可以表示多个可用资源的. --值为2的信号量也就是特殊的互斥锁了. 那么下 ...

  8. CentOS下apache绑定域名

    本文主要介绍在CentOS下apache绑定域名以及apache绑定多个域名,首先要找到apache的配置文件httpd.conf的位置.CentOS操作系统一般在 /etc/httpd/conf 下 ...

  9. WP多语言

    WP多语言.本地化 建立一个Resources文件夹,再建立两个文件夹en-US和zh-CN,(分别表示美国英语.中文中国),每个文件夹下再新建资源文件(.resx),在资源文件中添加示例信息 新建一 ...

  10. Android-adb 常用命令 和 sqlite

    Android开发环境中,ADB是我们进行Android开发经常要用的调试工具,它的使用当然是我们Android开发者必须要掌握的. ADB概述 Android Debug Bridge,Androi ...