【Linux】工具GCC G++编译器轻度使用(C++)

目录

一、关联知识背景

二、GCC如何的编译过程

【2.1】预处理(进行宏替换)

【2.2】编译(生成汇编)

【2.3】连接(生成可执行文件或库文件)

三、GCC命令的常用选项

四、动静态链接


一、关联知识背景

gccg++ 分别是 gnuc & c++ 编译器 gcc/g++ 在执行编译工作的时候,总共需要4步:

  • 预处理,生成 .i 的文件[预处理器cpp]

  • 将预处理后的文件转换成汇编语言, 生成文件 .s [编译器egcs]

  • 有汇编变为目标代码(机器代码)生成 .o 的文件[汇编器as]

  • 连接目标代码, 生成可执行程序 [链接器ld]

>>预处理(进行宏替换) >>编译(生成汇编)  >>汇编(生成机器可识别代码) >>连接(生成可执行文件或库文件) 

测试代码如下:

#include <stdio.h>

// 宏定义
#define M 1234
int main(){
    // 注释:
    // 我是注释。                                                                             
    printf("Hello World\n");
    printf("Hello World\n");
    printf("Hello World\n");
    printf("Hello World\n");
    printf("Hello World\n");
    printf("Hello World\n");
    printf("Hello World\n");

#ifdef SHOW 
    printf("Hollo Show\n");
#else
    printf("Hollo Default\n");
#endif
    printf("宏:%d\n", M);
    return 0;
}

【不编译宏定义】

gcc main.c -o execute
// 执行结果:
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hollo Default
宏:1234

【编译宏定义】

gcc main.c -o execute -DSHOW
// 执行结果:
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hollo Show
宏:1234

二、GCC如何的编译过程

【2.1】预处理(进行宏替换)

>> 指令:gcc -E main.c -o main.i
  • 预处理功能主要包括宏定义,文件包含,条件编译,去注释等 。

  • 预处理指令是以#号开头的代码行 。

  • 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。

  • 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序

【2.2】编译(生成汇编)

>> 指令:gcc –S main.i –o main.s
  • 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。

  • 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

【2.3】连接(生成可执行文件或库文件)

上面的三步只是在编译代码,需要把代码和c标准库的代码链接起来,代码才能执行,这个过程叫做链接。

>> 指令:gcc main.o –o myMain
// 查看结构
[shaxiang@VM-8-14-centos lesson]$ ls
main.c  main.i  main.o  main.s
// 生成可执行
[shaxiang@VM-8-14-centos lesson]$ gcc main.o -o myMain
[shaxiang@VM-8-14-centos lesson]$ ./myMain 
// main.c 源文件  main.i 预编译文件  main.s 编译文件  main.o 汇编文件  myMain 可执行文件
main.c  main.i  main.o  main.s  myMain
// 执行结果
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hollo Default
宏:1234

三、GCC命令的常用选项

选项 解释
-ansi 只支持 ANSI 标准的 C 语法。这一选项将禁止 GNU C 的某些特色, 例如 asm 或 typeof 关键词。
-c 只编译并生成目标文件。
-DMACRO 以字符串"1"定义 MACRO 宏。
-DMACRO=DEFN 以字符串"DEFN"定义 MACRO 宏。
-E 只运行 C 预编译器。
-g 生成调试信息。GNU 调试器可利用该信息。
-IDIRECTORY 指定额外的头文件搜索路径DIRECTORY。
-LDIRECTORY 指定额外的函数库搜索路径DIRECTORY。
-lLIBRARY 连接时搜索指定的函数库LIBRARY。
-m486 针对 486 进行代码优化。
-o FILE 生成指定的输出文件。用在生成可执行文件时。
-O0 不进行优化处理。
-O 或 -O1 优化生成代码。
-O2 进一步优化。
-O3 比 -O2 更进一步优化,包括 inline 函数。
-shared 生成共享目标文件。通常用在建立共享库时。
-static 禁止使用共享连接。
-UMACRO 取消对 MACRO 宏的定义。
-w 不生成任何警告信息。
-Wall 生成所有警告信息。

四、动静态链接

        我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?

        最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。

函数库一般分为静态库和动态库两种:

  • 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”。

  • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件。

gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。

file myMain     // 查看可执行文件的详细信息.
ldd myMain      // 查看可执行文件以来的动态库文件.

                在Linux环境下大多指令都是以来动态库的,所以说动态库很重要!

>> 命令:file /usr/bin/ls
>> 命令:file /usr/bin/pwd
>> 命令:file /usr/bin/which
>> 命令:ldd /usr/bin/ls

        在Linux下编译代码默认使用的就是动态链接库,那能不能用静态库进行编译呢?

>> 命令:gcc main.c -o myMain_s -static

一般来说静态库是需要自己安装的,这里列出静态库的安装方式:

  • 查看libc.a是否已经安装

>> 命令:sudo find / -name 'libc.a'  
  • 系统安装静态库

// centos系列安装
>> 命令:sudo yum install glibc-static   		// 安装C语言静态库
>> 命令:sudo yum install libstdc++-static   	// 安装C++语言静态库
// ubuntu系列安装
>> 命令:sudo apt-get install libc6-dev  
    
// 安装完成后,再次查看静态库
[shaxiang@VM-8-14-centos ~]$ sudo find / -name 'libc.a'
/usr/lib64/libc.a

猜你喜欢

转载自blog.csdn.net/lx473774000/article/details/132760457