[译] C track: compiling C programs.
原文:C track: compiling C programs.
C track: compiling C programs.
尽管有些计算机语言(如 Schema 或者 Basic)通常使用交互式的解释器(当你输入命令后,就可立即执行),但 C 语言不是。C 的源文件总是要通过一个叫做编译器(compiler)的程序编译成二进制代码然后运行。这就是我们接下来要详细说明的几个步骤。
几种不同类型的文件
你需要4种文件进行编译C 程序:
常规的源代码文件(source code)。 这些文件包含了函数定义,并约定以 "
.c
" 作为结尾进行命名。头文件(Header). 这些文件包含了函数声明(也叫做函数原型)以及各种预处理语句。源文件可以通过头文件访问外部定义的函数。头文件的文件名约定以 "
.h
" 作为结尾.目标文件(Object). 这些文件由编译器的输出而产生。目标文件包含了二进制形式的函数定义,本身是不可执行文件。目标文件的文件名约定以"
.o
" 结尾,尽管在一些操作系统,如(Windows, MS-DOS),经常以".obj
" 结尾。二进制可执行文件(Binary executables)。这些文件由一个叫做链接器(linker)的程序的输出而产生。链接器链接一些目标文件并产生可以直接执行的二进制文件。二进制可执行文件在 Unix 操作系统上没有后缀名,但在 Windows 上,通常以"
.exe
" 作为后缀名。
还有其他的各种文件,尤其是静态库文件(".a
" files or ".lib" on Windows)以及共享库文件(".so
" files or ".dll" on Windows)。但通常,你不需要直接与他们打交道。
预处理
在编译器开始编译源文件之前,源文件由预处理器(preprocessor)进行处理。预处理器是一个真实的单独的程序(通常叫做"cpp
", for "C preprocessor"),而由编译器在编译前自动调用。预处理器的工作就是讲源文件转换成另外一个源文件(你也可以认为是对源文件的修改或者扩展)。修改后的文件可能作为一个真实的文件存在文件系统中,也可能仅仅是在发送给编译器之前在内存中作短暂的保留。另外,你不需要特别关注预处理,但是你需要知道预处理是干什么滴。
预处理指令以符号("#
")开始. 在多种预处理指令中,有两种最为重要:
#define
. 主要用于定义常量。如,#define BIGNUM 1000000
指定在剩下的程序中任何位置处理的字符串 BIGNUM 应该被替换为 1000000。例如,这个语句:
int a = BIGNUM;
变成了
int a = 1000000;
#define
语句用于避免一个常量值在源文件中多处重复出现。这在你随后需要对这常量值进行修改时是相当的重要,并且可以减少bug 的滋生,你只需要对 #define 的定义修改,而不是对常量值在整个源代码中多处的出现位置进行修改。#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" 结尾的文件。 然而,目标文件并不能直接运行。为了能够生成可执行文件,你还需要加入被#include
d 包含的库函数代码(这个通过 #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.o
, bar.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 typinginfo gcc
.
[译] C track: compiling C programs.的更多相关文章
- Linux内核Makefile文件(翻译自内核手册)
--译自Linux3.9.5 Kernel Makefiles(内核目录documention/kbuild/makefiles.txt) kbuild(kernel build) 内核编译器 Thi ...
- Beginning Scala study note(1) Geting Started with Scala
1. Scala is a contraction of "scalable" and "language". It's a fusion of objecte ...
- linux内核的makefile.txt讲解
linux内核的linux-3.6.5\Documentation\kbuild\makefiles.txt Linux Kernel Makefiles This document describe ...
- CUDA1-hello world
电脑配置:windows7 sp1 64bit + CUDA6.5 + GeForce GTX780 Ti 显卡中的GPU因为多核可以处理很多相同的操作,相比较来说cpu就像个健全的手,什么活都能干 ...
- 安装coreseek找不到mysql
1.安装 coreseek-3.2.14 遇到问题:“ERROR: cannot find MySQL include files,随即在网上搜索各种答案说是要找到mysql.h的正确路径加入./co ...
- OpenMP for Fortran
OpenMP for Fortran OpenMP Directive Syntax of OpenMP compiler directive for Fortran: !$OMP Directive ...
- mysql 升级方法
Performing an In-place Upgrade This section describes how to perform an in-place upgrade. Review Bef ...
- 《 UNIX网络编程》源码的使用
学习编程这东西,看代码,改代码,运行代码这样才能学到实际东西!本书说在www.unpbook.com可以获取源码,不过打不开!所以google unpv13e.tar.gz 并在网络上找到了:源码:h ...
- 嵌入式Linux-GNU Make 使用手册(中译版)
GNU Make 使用手册(中译版) 翻译:于凤昌 译者注:本人在阅读Linux源代码过程中发现如果要全面了解Linux的结构.理解Linux的编程总体设计及思想必须首先全部读通Linux源代码中各级 ...
随机推荐
- LeetCode126:Word Ladder
题目: Given two words (start and end), and a dictionary, find the length of shortest transformation se ...
- Retention、Documented、Inherited三种注解
Retention注解 Retention(保留)注解说明,这种类型的注解会被保留到那个阶段. 有三个值:1.RetentionPolicy.SOURCE —— 这种类型的Annotations只在源 ...
- js限制input输入
1.取消按钮按下时的虚线框,在input里添加属性值 hideFocus 或者 HideFocus=true <input type="submit" value=" ...
- R 网页数据爬虫1
For collecting and analyzing data. [启示]本处所分享的内容均是笔者从一些专业书籍中学习所得,也许会有一些自己使用过程中的技巧.心得.小经验一类的,但远比不上书中所讲 ...
- 环境搭建二 secureCRT配置
上一篇里面讲到了虚拟机安装,以及secureCRT的远程连接.此篇文章介绍secureCRT的配置. 颜色设置 参考 http://jingyan.baidu.com/article/a681b0 ...
- j2ee log4j集中式日志解决方案logpool v0.3
V0.3相对于v0.2的更新如下:
- linux环形buff模拟多线程信号量操作
互斥锁mutex变量的值非0即1,只能用来表示两种状态下的临界资源.而信号量是与之类似的,用来表示可用资源的,区别在于,信号量可以表示多个可用资源的. --值为2的信号量也就是特殊的互斥锁了. 那么下 ...
- CentOS下apache绑定域名
本文主要介绍在CentOS下apache绑定域名以及apache绑定多个域名,首先要找到apache的配置文件httpd.conf的位置.CentOS操作系统一般在 /etc/httpd/conf 下 ...
- WP多语言
WP多语言.本地化 建立一个Resources文件夹,再建立两个文件夹en-US和zh-CN,(分别表示美国英语.中文中国),每个文件夹下再新建资源文件(.resx),在资源文件中添加示例信息 新建一 ...
- Android-adb 常用命令 和 sqlite
Android开发环境中,ADB是我们进行Android开发经常要用的调试工具,它的使用当然是我们Android开发者必须要掌握的. ADB概述 Android Debug Bridge,Androi ...