原文: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. Python入门笔记(11):集合

    一.目录 1.集合概述 2.关于集合的操作符.关系符号 3.集合的一系列操作(添加.更新.访问.删除) 4.关于集合的内建函数.内建方法 5.小结 二.集合概述 集合(set):把不同的元素组成一起形 ...

  2. jQuery实现隐藏标签

    要求:用户进入该页面时,品牌列表默认是精简显示,用户可以单击商品列表下方的“显示全部品牌”按钮来显示全部的品牌. <%@ Page Language="C#" Inherit ...

  3. c#调用Aspose.Word组件操作word 插入文字/图片/表格 书签替换套打

    由于NPOI暂时没找到书签内容替换功能,所以换用Apose.Word组件. using System; using System.Collections.Generic; using System.C ...

  4. asp.net.mvc4在vs2010怎样创建mvc项目及它的结构

    1.打开vs2012,创建mvc项目 文件-->新建--> 项目--> web--> asp.net.Mvc 4web应用程序-->基本模板

  5. 变废为宝,将Discuz废弃的cache机制引入到memory体系中

    Discuz的source/class/cache目录,代表着相应的缓存机制,但实际上废弃很多年了. Discuz用Memory代表了缓存,里面内置了memcache等多种缓存驱动. 但很多人的开发环 ...

  6. Java中Scanner类和BufferReader类之间的区别

    java.util.Scanner类是一个简单的文本扫描类,它可以解析基本数据类型和字符串.它本质上是使用正则表达式去读取不同的数据类型. Java.io.BufferedReader类为了能够高效的 ...

  7. lambda 个人学习理解

    lambda是简化代码量的写用更简单的方法来写匿名方法 lambda左边是参数,右边是代码块(方法执行语句). 整体运算结果是根据左边参数,执行右边语句,返回右边执行的结果: 匿名方法是简化方法 1. ...

  8. Virtual Environments for mac

    A Virtual Environment is a tool to keep the dependencies required by different projects in separate ...

  9. mybatis hellworld

    用maven来进行搭建项目的~~   1. 搭建环境 pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" x ...

  10. JavaScript焦点轮播图

    在慕课学习了JavaScript焦点轮播图特效,在此做一个整理. 首先是html结构,我用的是本地同文件夹下的三张图片,多出来的第一张(pic3副本)和最后一张图片(pic1副本)是为了实现无缝切换效 ...