前言
首先gcc与GCC要区分对待,GCC原名为GNU C Compiler,是一个C编译器的代号,但是后来不断地扩展,开始支持很多语言,GCC也就变成了编译器家族GNU Compiler Collection. 另外GNU的意思是GNU not Unix的递归简写(-_-所以那个G到底是啥意思?),这是一个由Stallman发起的一个操作系统计划,但是最后各种编译器什么的工具都写好了,核心的内核没有开发成功,但最后Linux填补了这个空白.
编译的四个阶段
如果只是在命令行编译一下c或c 程序,直接看后面的命令就可以了,但是了解一下编译的的过程,会加深对gcc的理解.
(环境:ubuntu 18.04 | 已安装gcc/g ) 1.预处理阶段 .c >>> .i 在这个阶段,编译器先把人方便看的程序处理成编译器方便看的程序.
#define删掉,然后展开所有宏定义
处理那些#include,把包含的那些头文件复制过来.
删掉注释
… 下面这个test.cpp
代码语言:javascript复制#include <iostream>
#include <cstdio>
#define AA a*a
using namespace std;
int main(){
int a=2;
int A=AA;//这里会用宏定义替换掉啊
cout<<A<<endl;
cout<<"hello world!"<<endl;
return 0;
}
用命令 g -E test.cpp -o test.i 处理一下生成tes.i文件 (不加-o,就都会输出到屏幕上,不生成.i文件)
代码语言:javascript复制此处省略两万行...
static ios_base::Init __ioinit;
}
# 2 "test.cpp" 2
# 1 "/usr/include/c /7/cstdio" 1 3
# 39 "/usr/include/c /7/cstdio" 3
# 40 "/usr/include/c /7/cstdio" 3
# 3 "test.cpp" 2
# 5 "test.cpp" //可以看到define,include
using namespace std; // 什么的都没了,被替换为了上面两万多行
int main(){
int a=2;
int A=a*a;//此处宏定义被替换了,注释也没了
cout<<A<<endl;
cout<<"hello world!"<<endl;
return 0;
}
2.编译为汇编代码 .i >>> .s 这一阶段,编译器进行:
- 语法分析
- 词法分析
- 生成汇编代码 通过命令 g -S test.i -o test.s 可以生成汇编代码,代码太长,就不粘贴了.
3.生成机器码 .s >>> .o 通过 g -c test.s -o test.o 生成目标文件,如果程序只有一个文件,这时候应该就可以执行了.如果有多个.o文件,还得需要下一步链接后再运行. 这一步也可以用GNU自带的汇编器as来将汇编文件生成机器码,命令如下:
代码语言:javascript复制as test.s -o test.o
这里可以借助hexdump工具来查看二进制文件
代码语言:javascript复制hexdump -C test.o > a.txt
vim a.txt
4.链接.o文件 .o >>> 可执行文件
代码语言:javascript复制g test.o -o test
./test #然后就可以运行文件了
gcc & g
这两个都是编译器的名字,一般看名字会感觉gcc用来编译c语言,g 用来编译c 的,但实际上这两个既能编译c语言,又能编译c ,g 可以算是gcc的另一个版本. 当gcc编译c程序时 gcc a.c -o a #这样就生成可执行文件a了 当gcc编译c 程序时 gcc a.cpp -lstdc #加个-lstdc 链接上c 的库才行. 当g 编译c程序时,跟gcc用法是一样的,实际上g 在编译c程序是也是直接调用的gcc 当g 编译cpp程序时,看下面一节.
最最常用的命令
无论编译.c还是.cpp,g 都挺方便,一般直接都用g 就可以了. 有时候只是想快速的运行一个c或cpp程序而已,就不用看上面那一坨了…直接用这条命令就够了:
代码语言:javascript复制g test.cpp -o test #cpp程序
./test #运行
------------------
g test.c op test #c程序
./test #
其他命令
代码语言:javascript复制g -c main.c #生成.o文件(.object)
g -c main.c -o main.o #生成指定名字的.o文件
g main.o #将main.o文件生成a.out文件(.obj >> .out)
常用选项
代码语言:javascript复制-E 只运行 C 预编译器。
-S 生成汇编代码
-c 只编译并生成目标文件。
-g 生成调试信息。GNU 调试器可利用该信息。
-IDIRECTORY 指定额外的头文件搜索路径DIRECTORY。
-LDIRECTORY 指定额外的函数库搜索路径DIRECTORY。
-lLIBRARY 连接时搜索指定的函数库LIBRARY。
-o FILE 生成指定的输出文件。用在生成可执行文件时。
-O0 不进行优化处理。
-O 或 -O1 优化生成代码。
-O2 进一步优化。
-O3 比 -O2 更进一步优化,包括 inline 函数。
-w 不生成任何警告信息。
-Wall 生成所有警告信息。
参考
C语言中文网 GCC编译c语言程序完整演示 c语言真正的编译过程 Linux查看二进制文件内容 GCC
欢迎与我分享你的看法。 转载请注明出处:http://taowusheng.cn/