概述
gcc
-E 则经过预编译 变成.i文件,还是c代码只是对#中进行字符串的展开和复制
-S 则经过编译 变成 .s文件,为汇编代码
-c 则经过汇编 变成.o文件,为二进制文件
然后 将许多(也许也就几个).o文件链接在一起
生成linux中的可执行文件.out
直接gcc会将上述整个
如果要在编译停下来用 -E
如果要在汇编停下来用 -s
在链接时停下来用 -c
C语言编译链接过程通常包括四个部分:预处理、编译、汇编和链接。
-
预处理
预处理是指对源代码进行宏替换,头文件引入等预处理操作的过程。预处理器会将所有以 # 开头的指令进行处理(例如 #include、#define 等),并将结果输出到一个临时文件中。
可以使用以下命令进行预处理:gcc -E file.c -o file.i
-
编译
编译器将预处理后的文件转换为汇编代码。在这个阶段,编译器会检查代码语法和语义是否正确,并对代码进行优化。编译器将 C 代码转换为汇编语言代码,并将结果输出到一个目标文件中。
可以使用以下命令进行编译:gcc -S file.i -o file.s
-
汇编
汇编器将汇编代码转换为可重定位的二进制目标文件。它会将汇编代码转换为机器代码,并生成目标文件。目标文件包含了机器指令、符号表以及其他一些与目标文件相关的信息。
可以使用以下命令进行汇编:gcc -c file.s -o file.o
-
链接
链接器将多个目标文件合并为一个可执行文件。在这个阶段,链接器会解决全局符号的定义和引用关系,并把这些目标文件合并为一个可执行文件。
可以使用以下命令进行链接:gcc file.o -o executable
objdump 是用来查看一个二进制文件的反汇编
预编译
‘#’ 是预编译代码的标识
如:#include
#define
展开或代替
gcc a.c --verbose
如上我们甚至能在printf 中写 #include
但是我们知道 #include只是在寻找文件并复制,那么就很好理解了
在预编译的情况下,变量是不用通过定义即可使用的
除非变量被定义了,否则就为空
aa==bb为空,所以这里是输出Yes
还有#if 这是有判断的功能的
再来看看宏定义:
A 是 'aaaaaaaaaa'
TEN(xxx) 使用TEN(xxx),那么xxx会被重复十遍(按照上面代码写的)
那么B 就是十个'aaaaaaaaaa'
C是 十个 B
.........
巧妙利用宏还可以写出精炼的代码:
链接
将上面两个.c文件经过编译变成.o文件后,可以用gcc 将其链接
其实我们#include时都是看到的如:
的定义
其实最后都是经过链接才能真正使用的
加载
任何类型的指针其首先都是一个纯粹的保存地址的地方
所以任何一个指针其都可以赋值给void *
int * , float * ......
其首先都是一个纯粹的指针,前面的int等是对 这个指针指向的地方的解读
当其中的数据参与运算时,就按照 int /float ...类型进行运算
main
和&main
的值相同,是因为函数名本身就是一个指向函数入口地址的指针。
注意这里main不是变量,也就是说没有花空间来保存main
main === &main
而argv
和&argv
的值不同,则是因为它们代表的是不同的变量。argv
是一个指向字符指针数组的指针,用于存储命令行参数。而&argv
是argv
这个指针本身的地址,也就是说它存储的是argv
指针变量在内存中的地址。
标签:文件,gcc,语言,代码,拾遗,编译,file,链接 From: https://www.cnblogs.com/cilinmengye/p/17299229.html