目录
1.背景知识
注:本篇的myfile只是为了方便讲解自己起的文件名。
gcc/g++是编译器——将文本文件翻译为二进制可执行文件。
程序的翻译可分为四个阶段:
- 预处理(头文件展开、条件编译、宏替换、去注释等,处理完还是c语言)
用gcc -E myfile.c -o myfile.i生成myfile.i,对比可发现.i文件比自己写的.c文件要多很多,多出的内容是将头文件中的内容拷贝到了源文件中——头文件展开。 - 编译(检查语法,生成汇编)
用gcc -S myfile.i -o myfile.s生成mufile.s,打开可发现代码又从.i的大文件变小了——生成了汇编。 - 汇编(生成机器可识别代码:汇编 -> 可重定位目标二进制文件bin.obj,且不可执行)
——只把我们自己的代码进行翻译形成二进制文件。
用gcc -c myfile.s -o myfile.o生成mufile.o,.o为目标二进制文件(与windows下的.obj对等),打开会发现都是乱码,并且不可执行。 - 链接(生成可执行文件或库文件)
——将我们自己的代码形成的.obj文件和库文件进行合并,形成可执行程序。
用gcc myfile.o -o myfile生成myfile(不用-o指定则会默认生成a.out),myfile为可执行文件。
补充:
1.有几个源文件(.c)就生成几个.obj文件;
2.头文件(.h)则在预处理阶段就合并到源文件的特定位置中了(头文件展开);
2.gcc/g++的用法
1.格式:gcc [选项] 要编译的文件 [选项] [目标文件]
如果不加选项对文件直接使用gcc,比如gcc myfile.c
,会把程序翻译的四个阶段一次直接走完,生成一个a.out
可执行文件,可以直接使用 ./a.out
对其进行执行。
[选项]:
-o :将生成的文件输出到指定名称的文件中。(-o后面必定跟自己想生成的文件名) 用法:gcc -o myfile myfile.c或者gcc myfile.c -o myfile,将gcc生成的a.out输出到myfile中。
-E :进行程序的翻译,但是在预处理结束就停止。 用法:gcc -E myfile.c -o myfile.i,将预处理生成的文件输出到myfile.i中。
-S :进行程序的翻译,但是在编译结束就停止。 用法:gcc -S myfile.c或gcc -S myfile.i,从.c文件或从.i文件执行都可以,默认输出到myfile.s文件。 也可以gcc -S myfile.c -o
mufile.s或gcc -S myfile.i -o mufile.s显式写出输出到.s文件中。-c : 进行程序的翻译,但是在汇编结束就停止。 用法:gcc -c myfile.c或gcc -c myfile.i或gcc -c myfile.s,从.c、.i、.s文件执行都可以,默认输出到myfile.o文件。 也可以gcc -c
myfile.c -o mufile.o或gcc -S myfile.i -o mufile.o或gcc -c
myfile.o显式写出输出到.o文件中。
3.指令补充
3.1.ldd指令
指令补充:
- ldd : ldd [可执行程序],查看可执行程序依赖了哪些库(只能看动态链接的库)
3.2.file指令
指令补充:
- file :file [选项] 文件或目录,可以查看文件的类型
[选项]:
-c 详细显示指令执行过程
-z 尝试去解读压缩文件的内容
4.Linux下的头文件、库
为什么在Linux下可以进行C\C++代码的编写与编译呢?
因为Linux已经携带了语言级别的头文件和语言对应的库。
- 头文件
在Linux下,头文件一般在/user/include
目录下。 - 库(Linux下)——使用
ldd [可执行文件]
可以查看程序链接库的地址
库分两种,静态库和动态库。库的名字是去掉前缀lib、去掉后缀.a/.so剩下的。
静态库:libXXX.a (windows下为.lib)
动态库:libXXX.so (windows下为.dll)
例如:查看ldd myfile ,其中有一行会显示libc.so.6 => /lib64/libc.so.6
,此时ls /lib64/libc.so.6 -al
查看文件的详细信息,会显示/lib64/libc.so.6 -> libc-2.17.so
发现这个库的名字是c-2.17,这个库就是c语言的c标准库。
(我们在windows下使用vs,安装软件时最重要的就是下载安装语言的头文件和库!)
4.1.指令的库
在Linux下,我们所使用的指令,相当一部分都是用C语言写的。
例如:
我们使用which ls查看ls的文件地址为/user/bin/ls,然后使用ldd
/user/bin/ls查看ls文件的库,可以发现其中也有libc.so.6 =>
/lib64/libc.so.6 C语言库,ls也是使用C语言写的。
也可以使用上述流程去查看别的指令的库,可以发现大部分语言都是使用C语言写的。
所以其实指令也是程序,和我们自己写的程序没有本质区别。
4.1.1.动态库
动态库 == 共享库
动态库被所有程序所共享,所以一般只有一份,并且具有只读属性,不允许别人修改。
如果动态库被删除,所有依赖这个动态库的程序都将无法正常运行。
在链接器链接的时候,只需要把库中对应程序的地址填到所需的地方就完成了链接。
4.1.2.静态库
将所需要的代码直接拷贝到自己的程序中。
连接成功后,如果库被删除,程序依旧可以运行。
4.1.3.动静态库的优缺点
动静态库的区别:
静态库–>拷贝所需代码本体–>直接在自己的程序中运行–>静态链接成功就不再依赖库,独立运行,库缺失也可运行。
动态库–>拷贝所需代码地址–>运行时需要跳转到库中–>动态链接成功还是需要依赖库,库缺失不能运行。
静态库:因为是拷贝代码本体,所以比较浪费空间。
动态库:因为可以被共享,永远在库中,程序中只有地址,比较节省空间。
5.gcc/g++静态链接与动态链接的方法
Linux默认使用的是动态链接与动态库!
如果想使用静态链接,要在编译时使用-static
选项:
- -static :使用静态链接库
例如:
gcc myfile.c -o myfile_static -static
(myfile_static是自定义文件名)
此时生成的文件,使用ldd myfile_static
是无法查看链接了哪些库的;
使用file myfile_static
查看文件信息,可以看到这个程序是静态链接的。
6.静态库的安装
一般的云服务器,默认都只有动态链接
使用yum install glibc-static libstdc++-static -y
可以进行c、c++静态库的安装。
(或者sudo执行)