C程序编译步骤详解.doc_第1页
C程序编译步骤详解.doc_第2页
C程序编译步骤详解.doc_第3页
C程序编译步骤详解.doc_第4页
C程序编译步骤详解.doc_第5页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C/C+程序编译步骤详解新一篇:MakefileC/C+语言很多人都比较熟悉,这基本上是每位大学生必学的一门编程语言,通常还都是作为程序设计入门语言学的,并且课程大多安排在大一。刚上大学,孩子们还都很乖,学习也比较认真,用心。所以,C/C+语言掌握地也都不错,不用说编译程序,就是写个上几百行的程序都不在话下,但是他们真的知道C/C +程序编译的步骤么?我想很多人都不甚清楚,如果他接下来学过“编译原理”,也许能说个大概。VC的“舒适”开发环境屏蔽了很多编译的细节,这无疑降低了初学者的入门门槛,但是也“剥夺”了他们“知其所以然”的权利,致使很多东西只能死记硬背,遇到相关问题就“丈二”。实际上,我也是在学习Linux环境下编程的过程中才逐渐弄清楚C/C+源代码是如何一步步变成可执行文件的。总体来说,C/C+源代码要经过:预处理、编译、汇编和连接四步才能变成相应平台下的可执行文件。大多数时候,程序员通过一个命令就能完成上述四个步骤。比如下面这段C的“Hello world!”代码:File: hw.c#include int main(int argc, char *argv) printf(Hello World!n); return 0;如果用gcc编译,只需要一个命令就可以生成可执行文件hw:xiaosuogentux hw $ gcc -o hw hw.cxiaosuogentux hw $ ./hw Hello World!我们可以用-v参数来看看gcc到底在背后都做了些什么动作:Reading specs from /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/specsConfigured with: /var/tmp/portage/sys-devel/gcc-3.4.6-r2/work/gcc-3.4.6/configure -prefix=/usr -bindir=/usr/i686-pc-linux-gnu/gcc-bin/3.4.6 -includedir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include -datadir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6 -mandir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6/man -infodir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.6/info -with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include/g+-v3 -host=i686-pc-linux-gnu -build=i686-pc-linux-gnu -disable-altivec -enable-nls -without-included-gettext -with-system-zlib -disable-checking -disable-werror -enable-secureplt -disable-libunwind-exceptions -disable-multilib -disable-libgcj -enable-languages=c,c+,f77 -enable-shared -enable-threads=posix -enable-_cxa_atexit -enable-clocale=gnuThread model: posixgcc version 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)/usr/libexec/gcc/i686-pc-linux-gnu/3.4.6/cc1 -quiet -v hw.c -quiet -dumpbase hw.c -mtune=pentiumpro -auxbase hw -version -o /tmp/ccYB6UwR.signoring nonexistent directory /usr/local/includeignoring nonexistent directory /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/././././i686-pc-linux-gnu/include#include . search starts here:#include search starts here:/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/include/usr/includeEnd of search list.GNU C version 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10) (i686-pc-linux-gnu) compiled by GNU C version 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.9).GGC heuristics: -param ggc-min-expand=81 -param ggc-min-heapsize=97004/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/././././i686-pc-linux-gnu/bin/as -V -Qy -o /tmp/ccq8uGED.o /tmp/ccYB6UwR.sGNU assembler version 2.17 (i686-pc-linux-gnu) using BFD version 2.17/usr/libexec/gcc/i686-pc-linux-gnu/3.4.6/collect2 -eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o hw /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/./././crt1.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/./././crti.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtbegin.o -L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6 -L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6 -L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/././././i686-pc-linux-gnu/lib -L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6/././. /tmp/ccq8uGED.o -lgcc -as-needed -lgcc_s -no-as-needed -lc -lgcc -as-needed -lgcc_s -no-as-needed /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtend.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/./././crtn.o稍微整理一下,去掉一些冗余信息后,如下:cc1 hw.c -o /tmp/ccYB6UwR.sas -o /tmp/ccq8uGED.o /tmp/ccYB6UwR.sld -o hw /tmp/ccq8uGED.o以上三个命令分别对应于编译步骤中的预处理+编译、汇编和连接。预处理和编译还是放在了一个命令(cc1)中进行的,可以把它再次拆分为以下两步:cpp -o hw.i hw.ccc1 hw.i -o /tmp/ccYB6UwR.s一个精简过的能编译以上hw.c文件的Makefile如下:.PHONY: cleanall: hwhw: hw.o ld -dynamic-linker /lib/ld-linux.so.2 -o hw /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtbegin.o hw.o -lc /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtend.o /usr/lib/crtn.ohw.o: hw.s as -o hw.o hw.shw.s: hw.i /usr/libexec/gcc/i686-pc-linux-gnu/3.4.6/cc1 -o hw.s hw.chw.i: hw.c cpp -o hw.i hw.cclean: rm -rf hw.i hw.s hw.o当然,上面Makefile中的一些路径是我系统上的具体情况,你的可能与我的不同。接下来我们按照编译顺序看看编译器每一步都做了什么。首先是预处理,预处理后的文件hw.i:# 1 hw.c# 1 # 1 ._extension_ typedef _quad_t _off64_t;_extension_ typedef int _pid_t;_extension_ typedef struct int _val2; _fsid_t;.extern int remove (_const char *_filename) _attribute_ (_nothrow_);extern int rename (_const char *_old, _const char *_new) _attribute_ (_nothrow_);.int main(int argc, char *argv)printf(Hello World!n);return 0;注:由于文件比较大,所以只留下了少部分具有代表性的内容。可以看见预处理器把所有要包含(include)的文件(包括递归包含的文件)的内容都添加到了原始的C源文件中,然后把其输出到输出文件,除此之外,它还展开了所有的宏定义,所以在预处理器的输出文件中你将找不到任何宏。这也提供了一个查看宏展开结果的简便方法。第二步“编译”,就是把C/C+代码“翻译”成汇编代码:.file hw.c .section .rodata.LC0: .string Hello World!n .text.globl main .type main, functionmain: pushl %ebp movl %esp, %ebp subl $8, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax subl %eax, %esp subl $12, %esp pushl $.LC0 call printf addl $16, %esp movl $0, %eax leave ret .size main, .-main .section .note.GNU-stack,progbits .ident GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)这个汇编文件比预处理后的C/C+文件小了很多,去除了很多不必要的东西,比如说没用到的类型声明和函数声明等。第三步“汇编”,将第二步输出的汇编代码翻译成符合一定格式的机器代码,在Linux上一般表现为ELF目标文件。xiaosuogentux hw $ file hw.ohw.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped最后一步“连接”,将上步生成的目标文件和系统库的目标文件和库文件连接起来,最终生成了可以在特定平台运行的可执行文件。为什么还要连接系统库中的某些目标文件(crt1.o, crti.o等)呢?这些目标文件都是用来初始化或者回收C运行时环境的,比如说堆内存分配上下文环境的初始化等,实际上crt也正是C RunTime的缩写。这也暗示了另外一点:程序并不是从main函数开始执行的,而是从crt中的某个入口开始的,在Linux上此入口是 _start。以上Makefile生成的是动态连接的可执行文件,如果要生成静态连接的可执行文件需要将Makefile中的相应段修改:hw: hw.o ld -m elf_i386 -static -o hw /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/crtbeginT.o -L/usr/lib/gcc/i686-pc-linux-gnu/3.4.6 -L/usr/i686-pc-linux-gnu/lib -L/usr/lib/ hw.o -start-group -lgcc -lgcc_eh -lc -end-group

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论