5.C语言 GCC总结

gcc(GNU编译器套件)_百度百科GCC(GNU Compiler Collection,GNU编译器套件)是由GNU开发的编程语言译器。GNU编译器套件包括C、C++、 Objective-C、 Fortran、Java、Ada和Go语言前端,也包括了这些语言的库(如libstdc++,libgcj等。)GCC的初衷是为GNU操作系统专门编写的一款编译器。GNU系统是彻底的自由软件。此处,“自由”的含义是它尊重用户的自由。https://baike.baidu.com/item/gcc/17570

 在使用gcc编译程序时,编译过程可以细分为4个阶段:
1.预处理(Pre-Processing)
2.编译(Compiling)
3.汇编(Assembling)
4.链接(Linking)

gcc -o main -v main.c
-v:vebose
//显示整个编译过程
//gcc -v xx(可执行)就会显示其编译过程中不同阶段的信息

1.预处理(Pre-Processing)

gcc -E main.c -o main.i
//-E:macro expansion 宏展开,.i:intermediate 中间产物
//没有-o main.i,则默认打印到标准输出

cpp main.c
//是gcc -E main.c的底层真正执行的命令
//cpp : C Preprocessor的缩写
命令
/usr/bin/x86_64-linux-gnu-cpp-9 main.c -o main.i

详细过程
[root@Orz 23:40 /mnt/d/linux/c]# whereis cpp
cpp: /usr/bin/cpp /usr/lib/cpp /usr/share/man/man1/cpp.1.gz

[root@Orz 23:40 /mnt/d/linux/c]#  ll /usr/bin/cpp
lrwxrwxrwx 1 root root 5 Mar 20  2020 /usr/bin/cpp -> /usr/bin/cpp-9

[root@Orz 23:40 /mnt/d/linux/c]# ll /usr/lib/cpp
lrwxrwxrwx 1 root root 21 Nov 16 03:00 /usr/lib/cpp -> /etc/alternatives/cpp*

[root@Orz 23:42 /mnt/d/linux/c]# ll /etc/alternatives/cpp
lrwxrwxrwx 1 root root 12 Nov 16 03:00 /etc/alternatives/cpp -> /usr/bin/cpp*

[root@Orz 23:43 /mnt/d/linux/c]# ll /usr/bin/cpp-9
lrwxrwxrwx 1 root root 22 Aug  8  2020 /usr/bin/cpp-9 -> x86_64-linux-gnu-cpp-9*

[root@Orz 23:44 /mnt/d/linux/c]# ll /usr/bin/x86_64-linux-gnu-cpp-9
-rwxr-xr-x 1 root root 1158288 Aug  8  2020 /usr/bin/x86_64-linux-gnu-cpp-9*


[root@Orz 23:49 /usr/bin]# ll /usr/bin | grep "gcc"
-rwxr-xr-x 1 root   root         428 May  7  2006 c89-gcc*
-rwxr-xr-x 1 root   root         454 Apr 11  2011 c99-gcc*
lrwxrwxrwx 1 root   root           5 Mar 20  2020 gcc -> gcc-9*
lrwxrwxrwx 1 root   root          22 Aug  8  2020 gcc-9 -> x86_64-linux-gnu-gcc-9*
lrwxrwxrwx 1 root   root           8 Mar 20  2020 gcc-ar -> gcc-ar-9*
lrwxrwxrwx 1 root   root          25 Aug  8  2020 gcc-ar-9 -> x86_64-linux-gnu-gcc-ar-9*
lrwxrwxrwx 1 root   root           8 Mar 20  2020 gcc-nm -> gcc-nm-9*
lrwxrwxrwx 1 root   root          25 Aug  8  2020 gcc-nm-9 -> x86_64-linux-gnu-gcc-nm-9*
lrwxrwxrwx 1 root   root          12 Mar 20  2020 gcc-ranlib -> gcc-ranlib-9*
lrwxrwxrwx 1 root   root          29 Aug  8  2020 gcc-ranlib-9 -> x86_64-linux-gnu-gcc-ranlib-9*
lrwxrwxrwx 1 root   root           5 Mar 20  2020 x86_64-linux-gnu-gcc -> gcc-9*
-rwxr-xr-x 1 root   root     1154192 Aug  8  2020 x86_64-linux-gnu-gcc-9*
lrwxrwxrwx 1 root   root           8 Mar 20  2020 x86_64-linux-gnu-gcc-ar -> gcc-ar-9*
-rwxr-xr-x 1 root   root       35464 Aug  8  2020 x86_64-linux-gnu-gcc-ar-9*
lrwxrwxrwx 1 root   root           8 Mar 20  2020 x86_64-linux-gnu-gcc-nm -> gcc-nm-9*
-rwxr-xr-x 1 root   root       35464 Aug  8  2020 x86_64-linux-gnu-gcc-nm-9*
lrwxrwxrwx 1 root   root          12 Mar 20  2020 x86_64-linux-gnu-gcc-ranlib -> gcc-ranlib-9*
-rwxr-xr-x 1 root   root       35464 Aug  8  2020 x86_64-linux-gnu-gcc-ranlib-9*

使用-E参数可以让gcc在预处理结束后停止编译过程,

工作内容:

1.处理#include预编译指令:递归地引入要include的文件,insert到预编译指令所在的位置

2.处理条件预编译指令:比如#if、#ifdef、#elif、#else、#endif,分析逻辑关系,然后删除这些预编译指令,只留下想要的代码

3.对#define预处理命令,进行宏展开,也就是字面值替换

4.把所有的注释全部删除

5.添加行号和文件名标识,以便于在编译过程中产生编译错误或者调试时都能够生成行号信息。

预处理器(cpp)根据以字符#开头的命令,修改原始的C程序,把宏定义进行替换。

另外可以使用gcc main.c -I 头文件的路径 -o main

2.编译(Compiling)

gcc -S main.i -o main.s

命令
/usr/lib/gcc/x86_64-linux-gnu/9/cc1 -quiet -v -imultiarch x86_64-linux-gnu main.c -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase main -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o main.s

详细过程
[root@Orz 00:09 /mnt/d/linux/c]# ll /usr/lib/gcc/x86_64-linux-gnu/9/cc1
-rwxr-xr-x 1 root root 25654616 Aug  8  2020 /usr/lib/gcc/x86_64-linux-gnu/9/cc1

编译器(cc1)将文本文件main.i文件看成是预处理后的C语言源代码,再翻译成文本文件main.s,它包含一个汇编语言程序。

3.汇编(Assembling)

gcc -c main.s -o main.o

as -v --64 -o main.o main.s

命令
/usr/bin/x86_64-linux-gnu-as -v --64 -o main.o main.s

详细过程
[root@Orz 00:03 /mnt/d/linux/c]# whereis as
as: /usr/bin/as /usr/share/man/man1/as.1.gz
[root@Orz 00:04 /mnt/d/linux/c]# ll /usr/bin/as
lrwxrwxrwx 1 root root 19 Oct 20 19:09 /usr/bin/as -> x86_64-linux-gnu-as*
[root@Orz 00:05 /mnt/d/linux/c]# ll /usr/bin/x86_64-linux-gnu-as
-rwxr-xr-x 1 root root 696624 Oct 20 19:09 /usr/bin/x86_64-linux-gnu-as*

汇编器(as)将main.s翻译成机器语言指令,把这些指令打包成一种可重定位目标程序的格式,并将结果保存在目标文件main.o中。main.o文件是一个二进制文件,它的字节编码是机器语言指令而不是字符,如果我们在文本文件中打开main.o文件,看到的将是一堆乱码。

4.链接(Linking)

gcc -v main.o -o main 可以看见详细过程

命令
/usr/lib/gcc/x86_64-linux-gnu/9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccZ7lCdk.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o main /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. main.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o

 1779  whereis ld
 1780  ll /usr/bin/ld
 1781  ll /usr/bin/x86_64-linux-gnu-ld
 1782  ll /usr/bin/x86_64-linux-gnu-ld.bfd

链接器(ld)负责处理合并目标代码,生成一个可执行目标文件,可以被加载到内存中,由系统执行

GCC基本使用方法、常用指令

gcc [options] [filenames] -o [outputfilename]
/*其中options就是编译器所需要的参数;filenames给出相关的文件名称,可同时给出多个文件;
outputfilename为生成文件名称。*/

[options]
-c:通知gcc取消连接步骤,即编译源码并在最后生成目标文件
-Dmacro:定义指定的宏,使它能够通过源码中的#ifdef进行检验
-E:不经过编译预处理程序的输出而输送至标准输出
-g3:获得有关调试程序的详细信息,它不能与-o选项联合使用
-Idirectory:在包含文件搜索路径的起点处添加指定目录
-llibrary:提示连接程序在创建最终可执行文件时包含指定的库
-O、-O2、-O3:将优化状态打开,该选项不能与-g选项联合使用
-S:要求编译程序生成来自源代码的汇编程序输出
-v:启动所有警报
.h:预处理文件(标头文件)
-Wall:在发生警报时取消编译操作,即将警报看作是错误
-w:禁止所有的报警

(2条消息) GCC_人生代码 ---- 公众号-CSDN博客https://blog.csdn.net/qq_36772866/article/details/91126586?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163695872216780357234289%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163695872216780357234289&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-4-91126586.first_rank_v2_pc_rank_v29&utm_term=gcc&spm=1018.2226.3001.4187

HelloWorld背后的故事:在Linux上编译C语言程序_朝闻道-夕死可矣的博客-CSDN博客C语言的经典程序“Hello World”并不难写,很多朋友都可以闭着眼将它写出来。那么编译一个“Hello World”到底经历了怎样的过程呢?从源代码到可执行文件我们将这个文件命名为hello.c:#include <stdio.h>int main() { printf("Hello World\n"); return 0;}程序的第一行引用了stdio.h,stdio.h里有一些C标准库预定义好的方法,比如printf()方法,...https://blog.csdn.net/jc_benben/article/details/113945697

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值