一个c语言程序从源文件到生成可执行文件,编译器需要共经历4个步骤:
1) 预处理:把c文件中预处理命令扫描处理完毕,即对源代码文件中的文件包含(#include)、预编译语句(如宏定义#define等)进行分析,此时生成的文件仍然是可读的。
2) 编译:把预处理后的结果编译成汇编或者目标模块,即生成汇编语言文件,此时生成的文件仍然是可读的汇编文件。
3) 汇编:把编译出来的结果汇编成具体CPU上的目标代码模块,也即此时转换成具体的机器语言代码,此时生成的文件是不可读的非文本文件。
4) 连接:把多个目标代码模块连接生成一个大的目标模块,即将多个上面产生的机器代码文件(与其它的机器代码文件和库文件)汇集成一个可执行的二进制代码文件。

gcc作为c语言在linux下很著名的编译软件,分别有如下option来支持4个步骤:

名称               gcc选项英文名称                   gcc调用的程序示例
  预处理  -E       Pre-Processing  cpp             gcc -E test.c -o test.i
  编译  -S          Compiling         ccl               gcc -S test.i  -o test.s 
  汇编  -c          Assembling        as               gcc -c test.s  -o test.o
  连接  无          Linking              ld                gcc     test.o  -o test

说明:

gcc在编译c语言文件时,首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(#include)、预编译语句(如宏定义#define等)进行分析;其次调用ccl进行编译工作,将文件编译成汇编语言文件,此时文件依旧是可读的;之后调用as进行汇编工作,将具体的汇编语言文件编译成cpu可执行的目标代码,此时文件不可读了;当所有的目标文件都生成之后,gcc就调用ld来完成最后的关键性工作,链接。在链接阶段,所有的目标文件被安排在可执行程序中的恰当的位置,同时,该程序所调用到的库函数也从各自所在的库中链接到合适的地方。下面对上面4个过程做下分别的说明:

1、在预处理阶段,如果不用“-o”指定文件名,那么会默认将预处理结果输出到标准终端设备。

[root@dbbak tmp]# cat a.c
int main()
{
        printf("shengtong test!\n");
}

[root@dbbak tmp]# gcc -E a.c
# 1 "a.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "a.c"
int main()
{
        printf("shengtong test!\n");
}
[root@dbbak tmp]# gcc -E a.c -o a.i
[root@dbbak tmp]# cat a.i
# 1 "a.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "a.c"
int main()
{
        printf("shengtong test!\n");
}

2、在编译阶段,如果不用“-o”指定文件名,那么默认会生成一个“*.s”的汇编语言文件。

[root@dbbak tmp]# gcc -S a.i
[root@dbbak tmp]# ls
a.c  a.i  a.s
[root@dbbak tmp]# gcc -S a.i -o a1.s
[root@dbbak tmp]# ls
a.c  a.i  a.s  a1.s

[root@dbbak tmp]#
[root@dbbak tmp]# cat a.s
        .file   "a.c"
        .section        .rodata
.LC0:
        .string "shengtong test!\n"
        .text
.globl main
        .type   main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        subl    %eax, %esp
        subl    $12, %esp
        pushl   $.LC0
        call    printf
        addl    $16, %esp
        leave
        ret
.Lfe1:
        .size   main,.Lfe1-main
        .section        .note.GNU-stack,"",@progbits
        .ident  "GCC: (GNU) 3.2.3 20030502 (Red Hat Linux 3.2.3-42)"
[root@dbbak tmp]# cat a1.s
        .file   "a.c"
        .section        .rodata
.LC0:
        .string "shengtong test!\n"
        .text
.globl main
        .type   main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        subl    %eax, %esp
        subl    $12, %esp
        pushl   $.LC0
        call    printf
        addl    $16, %esp
        leave
        ret
.Lfe1:
        .size   main,.Lfe1-main
        .section        .note.GNU-stack,"",@progbits
        .ident  "GCC: (GNU) 3.2.3 20030502 (Red Hat Linux 3.2.3-42)"

3、在汇编阶段,如果不用“-o”指定文件名,那么默认会生成一个“*.o”的机器语言代码文件。

[root@dbbak tmp]# gcc -c a.s
[root@dbbak tmp]# ls
a.c  a.i  a.o  a.s  a1.s
[root@dbbak tmp]# gcc -c a1.s -o a1.o
[root@dbbak tmp]# ls
a.c  a.i  a.o  a.s  a1.o  a1.s
[root@dbbak tmp]#
[root@dbbak tmp]# file a.o
a.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
[root@dbbak tmp]# file a1.o
a1.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

4、在连接阶段,不指定前面3个选项就是默认进入这个阶段,如果不用“-o”指定文件名,那么默认会生产一个“a.out”的可执行文件。

[root@dbbak tmp]# gcc a.o
[root@dbbak tmp]# ls
a.c  a.i  a.o  a.out  a.s  a1.o  a1.s  -- 可执行文件
[root@dbbak tmp]# gcc a1.o -o a1.out
[root@dbbak tmp]# ls
a.c  a.i  a.o  a.out  a.s  a1.o  a1.out  a1.s
[root@dbbak tmp]#
[root@dbbak tmp]# ./a.out
shengtong test!
[root@dbbak tmp]# ./a1.out
shengtong test!

5、编译c文件的时候,可以跳过前面阶段而直接进入后面阶段,如可以不分开执行预处理命令gcc -E test.c,而直接进入编译环节gcc -S test.c -o test.s,gcc会在执行“编译”环节(后面阶段)的时候发现没有“预编译”环节(前面阶段),它会自动补上。

gcc能够编译的语言文件有很多(常见的如c语言和c++语言等),它默认情况下依据文件的后缀名执行相应的编译,下面列出c和c++的:
.c 为后缀的文件,C语言源代码文件;
.i 为后缀的文件,是已经预处理过的C源代码文件;
.s 为后缀的文件,是汇编语言源代码文件;
.o 为后缀的文件,是编译后的目标文件;
.h 为后缀的文件,是程序所包含的头文件;
.a 为后缀的文件,是由目标文件构成的库文件;

.C .cc .cp .cpp .c++ .cxx 为后缀的文件,是C++源代码文件;
.ii 为后缀的文件,是已经预处理过的C++源代码文件;
.m 为后缀的文件,是Objective-C源代码文件;
.mi 是已经预处理过的Objective-C源代码文件;
.S 为后缀的文件,是经过预编译的汇编语言源代码文件。

当然,你可以乱写自己的文件名后缀,如将c文件以.cpp结尾或者以.eng结尾,那么gcc就无法根据后缀名来做正确的编译了,此时怎么办?gcc提供了“-x”选项来指定文件类型,“-x”选项内容有(只列出c和c++的):

c  c-header  cpp-output
c++  c++-cpp-output
objective-c  objc-cpp-output
assembler  assembler-with-cpp

当使用了“-x”选项后,那么其后面所有的文件都默认是其指定的文件类型,直到用“-x none”来指定结束。

[root@dbbak tmp]# gcc -x c -E a.sql -o a.i
[root@dbbak tmp]# cat a.i
# 1 "a.sql"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "a.sql"
int main()
{
        printf("shengtong test!\n");
}
[root@dbbak tmp]# mv c.sql c.c
[root@dbbak tmp]#
[root@dbbak tmp]# gcc -x c -S a.sql b.sql -x none  -S c.c
[root@dbbak tmp]# ls
a.i  a.s  a.sql  b.s  b.sql  c.c  c.s

下面再介绍下gcc的其他常用选项:

-pass-exit-codes
    Normally the gcc program will exit with the code of 1 if any phase of the compiler returns a non-success return code.  If you specify -pass-exit-codes, the gcc program will instead return with numeri-cally highest error produced by any phase that returned an error indication.
通常如果编译器遇到错误,返回值1;如果你想返回具体的错误代码,请用它。

-o file
    Place output in file file.  This applies regardless to whatever sort of output is being produced, whether it be an executable file,an object file, an assembler file or preprocessed C code.

Since only one output file can be specified, it does not make sense to use -o when compiling more than one input file, unless you are producing an executable file as output.

If -o is not specified, the default is to put an executable file in a.out, the object file for source.suffix in source.o, its assembler file in source.s, and all preprocessed C source on standard output.  -- 这段话我在上面的1/2/3/4/5中已经介绍了

-v

Print (on standard error output) the commands executed to run the stages of compilation.  Also print the version number of the com-piler driver program and of the preprocessor and the compiler proper.

这个选项的作用是把gcc编译c文件的过程给打印出来,如下面这个例子:

[root@dbbak tmp]# gcc -v a.c
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux
Thread model: posix
gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-42)
 /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/cc1 -lang-c -v -D__GNUC__=3 -D__GNUC_MINOR__=2 -D__GNUC_PATCHLEVEL__=3 -D__GXX_ABI_VERSION=102 -D__ELF__ -Dunix -D__gnu_linux__ -Dlinux -D__ELF__ -D__unix__ -D__gnu_linux__ -D__linux__ -D__unix -D__linux -Asystem=posix -D__NO_INLINE__ -D__STDC_HOSTED__=1 -Acpu=i386 -Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i386__ a.c -quiet -dumpbase a.c -version -o /tmp/cclLW8Ji.s
GNU CPP version 3.2.3 20030502 (Red Hat Linux 3.2.3-42) (cpplib) (i386 Linux/ELF)
GNU C version 3.2.3 20030502 (Red Hat Linux 3.2.3-42) (i386-redhat-linux)
        compiled by GNU C version 3.2.3 20030502 (Red Hat Linux 3.2.3-42).
ignoring nonexistent directory "/usr/i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/include
 /usr/include
End of search list.
 as -V -Qy -o /tmp/ccRCof2i.o /tmp/cclLW8Ji.s
GNU assembler version 2.14.90.0.4 (i386-redhat-linux) using BFD version 2.14.90.0.4 20030523
 /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crt1.o /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crti.o /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/crtbegin.o -L/usr/lib/gcc-lib/i386-redhat-linux/3.2.3 -L/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../.. /tmp/ccRCof2i.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/crtend.o /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crtn.o

上面的调用堆栈,充分反应了gcc编译过程,首先调用ccl执行预处理和编译,并且在/tmp目录下生成一个临时文件/tmp/cclLW8Ji.s文件;接着调用as执行汇编功能,也生成了临时文件/tmp/ccRCof2i.o;最后执行连接工作。

如果你只想看gcc的调用堆栈过程而不真正执行编译工作,怎么办?用“-###”选项:

-###
    Like -v except the commands are not executed and all command argu-ments are quoted.  This is useful for shell scripts to capture the driver-generated command lines.

从上面的过程中,我们可以看到,在各个步骤中gcc生成了中间临时文件,而如果你不想生成这些临时文件,而取而代之用管道,该怎么办?用“-pipe”选项:

-pipe
    Use pipes rather than temporary files for communication between the various stages of compilation.  This fails to work on some systems where the assembler is unable to read from a pipe; but the GNU assembler has no trouble.

举个例子如下,请看红色部分的管道:

[root@dbbak tmp]# gcc -### -pipe a.c
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux
Thread model: posix
gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-42)
 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/cc1" "-lang-c" "-D__GNUC__=3" "-D__GNUC_MINOR__=2" "-D__GNUC_PATCHLEVEL__=3" "-D__GXX_ABI_VERSION=102" "-D__ELF__" "-Dunix" "-D__gnu_linux__" "-Dlinux" "-D__ELF__" "-D__unix__" "-D__gnu_linux__" "-D__linux__" "-D__unix" "-D__linux" "-Asystem=posix" "-D__NO_INLINE__" "-D__STDC_HOSTED__=1" "-Acpu=i386" "-Amachine=i386" "-Di386" "-D__i386" "-D__i386__" "-D__tune_i386__" "a.c" "-quiet" "-dumpbase" "a.c" "-o" "-" |
 "as" "-Qy" "-o" "/tmp/cc8lJo7Z.o" "-"
 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/collect2" "--eh-frame-hdr" "-m" "elf_i386" "-dynamic-linker" "/lib/ld-linux.so.2" "/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crt1.o" "/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crti.o" "/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/crtbegin.o" "-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.3" "-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../.." "/tmp/cc8lJo7Z.o" "-lgcc" "-lgcc_eh" "-lc" "-lgcc" "-lgcc_eh" "/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/crtend.o" "/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crtn.o"

--help
    Print (on the standard output) a description of the command line options understood by gcc.  If the -v option is also specified then --help will also be passed on to the various processes invoked by gcc, so that they can display the command line options they accept. If the -W option is also specified then command line options which have no documentation associated with them will also be displayed.

--target-help
    Print (on the standard output) a description of target specific command line options for each tool.

--version
    Display the version number and copyrights of the invoked GCC.

转载于:https://www.cnblogs.com/ajian005/archive/2012/11/17/2841138.html

linux gcc编译C程序 分享相关推荐

  1. linux如何用gcc编译c程序,Ubuntu之如何使用gcc编译C语言程序

    在大学里面大家都用过VC6.0来进行编程.VC6.0属于集成开发环境,一份代码从文本变成可执行的程序只需要在其中点击几个按钮就行了,加之老师也只教过我们如何操作,并未介绍C语言的执行过程.上一篇曾提到 ...

  2. linux下软件编译终止,[2018年最新整理]linux下编译运行程序命令大全.ppt

    [2018年最新整理]linux下编译运行程序命令大全 1. 项目课题引入 2. Vi编辑器的使用方法 3. Linux中C语言程序的编辑 4. Linux中C语言程序的运行 5. 现场演示案例 课题 ...

  3. 在linux 下编译c程序时“ error:dereferencing pointer to incomplete type”的问题

    在linux 下编译c程序时经常会遇到" error:dereferencing pointer to incomplete type"的问题,该问题的原因是:结构体定义不规范造成 ...

  4. Linux错误27,解决在linux下编译32程序出现“/usr/include/gnu/stubs.h:7:27: 致命错误:gnu/stubs-32.h:没有那个文件或目录问题”...

    centos64位编译32位代码,出现/usr/include/gnu/stubs.h:7:27: 致命错误:gnu/stubs-32.h:没有那个文件或目录,需要安装32位的glibc库文件. 安装 ...

  5. win7 上面 gcc 编译的程序 a exe 运行的时候报错 a exe 已停止工作, 异常代码 c0000005

    win7 上面 gcc 编译的程序 a.exe 运行的时候报错 a.exe 已停止工作, 异常代码:c0000005: 原因分析: 一开始我以为是我的代码的问题,后来查询了这个错误码发现原来是兼容性的 ...

  6. c语言conflicting types,gcc编译C程序出现”error conflicting types for function”编译错误的分析解决...

    今天使用gcc编译C语言程序时出现 "error conflicting types for function" 编译错误,这个错误的原因是什么?如何解决?以下看正文的讲解. 在使 ...

  7. Linux gcc编译c/c++基本过程

    Linux系统下开发c++程序,那么gcc编译器就是我们绕不过去的一道坎.gcc是GNU出品的一款可以在多种硬件平台上编译处可执行程序的超级编译器,其执行效率比普通的编译器要高出20%~30%左右,而 ...

  8. Linux gcc编译简介、常用命令

    gcc作为linux平台下的标准C编译器,功能很强大.格式如下: gcc [option] [filename] -x language 指定使用的语言 -c 对文件进行编译和汇编,但不进行连接 -S ...

  9. 使用gcc编译和链接C语言程序,用GCC编译链接程序--编译链接器GCC常用功能(菜鸟级)...

    转载自:http://daimajishu.iteye.com/blog/1089740 对gcc认识的一篇文章,就转载了,截取了自己感兴趣部分. 一,GCC编译器简介 虽然我们称Gcc是C语言的编译 ...

最新文章

  1. Jenkins中连接Git仓库时提示:无法连接仓库:Error performing git command: git ls-remote -h
  2. MVC源码学习之AuthorizeAttribute
  3. 盘点国内互联网圈中程序员出身的商业大佬,看谁主沉浮!
  4. BIOS详情设置续一
  5. Git 有时候推送以及拉去不了代码解决方式(二)
  6. 恒温控制系统单片机仿真c语言,基于51单片机的恒温控制系统
  7. 微信小程序原生自定义组件布局问题
  8. SAS 金融函数 PMT IRR
  9. 如果宁静是Oracle,那万茜,张雨绮,黄圣依 是什么?(附姐姐信息表)
  10. 小程序推送代码到远程库
  11. 解决引用百度地图点击详情无法定位到相应位置问题
  12. 再不复工,公司就要发现没有我们也能正常运转了
  13. comp3311辅导 assignment1
  14. 计算机网络技术基础 阚宝明,计算机网络技术基础阚宝明答案
  15. java操作redis简单示例
  16. 2021世界燕窝展|上海滋补品展谈孕期燕窝六问
  17. 2020研究生数模竞赛思路
  18. 自制预防校园暴力的智能监控系统:远程连接,将前后端部署到CentOS服务器
  19. 腾讯、阿里、百度等互联网巨头究竟如何布局元宇宙的?
  20. 安装Adobe Illustrator(AI) CC 2017 后弹出quot;无法启动此程序,因为计算机中丢失api-ms-win-crt-runtime-l1-1-0.dllquot;

热门文章

  1. 文件隐藏服务器版本信息,如何隐藏Apache版本号和其他敏感信息
  2. 计算机办公应用软件初级,电脑办公软件有哪些?桌面便签办公软件基础教程
  3. 《零基础》MySQL 选择数据库(七)
  4. oracle模糊查询很慢,采用全文索引解决模糊查询速度慢的问题
  5. Pycharm最新版本安装教程
  6. python基础(16)之 日期
  7. youcans 的 OpenCV 学习课—6.灰度变换与直方图处理
  8. 【转】常用的风控算法模型评价指标
  9. word2016能识别linux换行符,word文章中的换行符如何批量替换为回车符
  10. java不大于6位_末尾带4的完全平方数的数量并且打印输出_Java计算一个数加上100是完全平方数,加上168还是完全平方数...