今天不学习,明天变垃圾。
头文件拷贝,去注释,条件编译,宏替换
-E让程序翻译到预处理阶段就停下来,-o指明形成的临时文件名称。
gcc test.c -E -o test.i
/usr/include/stdio.h //linux下的头文件路径
C:\Program Files\Microsoft Visual Studio\2022\Community\SDK\ScopeCppSDK\vc15\SDK\include\ucrt\stdio.h
//我的windows下的头文件路径
预处理之后的文件中多出来的一大堆代码其实是从linux中的/usr/include/stdio.h头文件路径下的头文件stdio.h中拷贝过来的,从头文件stdio.h中就可以找到printf函数的声明,具体的实现在C标准函数库里面
gcc test.c -DSHOW //标识符在命令行中定义
从下面图片便可以看出预处理阶段进行的4个步骤,删除注释,拷贝头文件,条件编译,宏替换
头文件最大的意义:1.写代码 2.支持代码自动补齐
-S进行程序的编译工作,做完编译工作,变成汇编语言之后,就停下来!
gcc -S test.i -o test.s
-c进行程序的汇编工作,做完汇编工作,变成可重定向目标二进制文件,就停下来!
gcc -c test.s -o test.o
od test.o //将二进制文件以二进制形式打印到显示器上
./test.o //运行二进制文件
可以看到我们无法执行这个二进制文件,其实是因为我们的文件中的一些库函数还没有成功的调用,现在仅仅只有这些库函数的声明,这些声明就在拷贝的头文件里面,而库函数的实现在标准库里面,链接阶段会帮助我们将标准库动态链接到我们的程序里面,之后程序才可以正常的运行。
最后,为了方便大家记忆指令的选项和生成的文件后缀名,这里教一下大家如何去记,ESc正好就是退出键,iso是镜像文件的后缀名
下面指令就是将我们汇编后的可重定向目标二进制文件进行链接,并且将链接过后的文件指明为mytest文件名
gcc test.o -o mytest
a.链接的本质:无非就是我们在调用库函数的时候,与标准库如何关联的这么一个问题!
b.关联的方式有两种:动态链接和静态链接
链接的时候,不是与标准库产生关联,而是将程序内部要用的方法,给程序拷贝一份,这样就完成了静态链接。
优势:不受库升级或者被删除的影响,这里当然指的是形成可执行二进制程序之后不受删除的影响,如果形成之前被删除的话,拷贝也拷贝不了了。
劣势:形成的可执行程序体积太大,网络、磁盘、内存的资源占用量大,
通过编译器内部的链接器,来链接标准函数库,值得注意的是,动态链接的时期是在程序运行的时候,如果程序需要链接,链接器就会链接标准函数库
优势:动态链接形成的可执行程序小,在内存、磁盘、网络等方面可以节省资源,与静态链接相比,这是决定性的优势。
file mytest // 查看可执行程序的详细信息
ldd mytest // 查看可执行程序依赖的动态库列表
在linux下库的命名:
动态库:lib作为前缀,.so作为后缀,
静态库:lib作为前缀,.a作为后缀,
去掉前缀和后缀,剩下的就是库名称!
stdio的std就是standard标准的意思
用这个库的程序非常多,但是库只有一份,所有用C语言写的程序,就不会出现重复的库代码,所以如果以后我们要下载一个C程序,还用下载C标准库吗?答案是不用的,因为我们系统里边只要有一份库就够使用了,但如果是静态链接的C程序的话,情况就不一样了,一下载就内存占用超大。
动态库默认系统里就有,静态库不一定有
静态链接,拷贝的是.a静态库的代码,所以如果想要实现静态链接,系统里就必须存在.a结尾的静态库
一般而言,为什么系统会自动携带动态库?因为光系统程序运行就需要动态库
sudo yum install glibc-static -y // 下载c标准静态库
sudo yum install -y libstdc++-static // 下载C++标准静态库
gcc mytest.c -o mytest -static // gcc实现静态链接
g++ mytest.c -o mytest -static // g++实现静态链接
系统给我们提供标准库的.h文件,这些.h文件里面有方法,它可以告诉我们怎么用这些库函数。
系统还给我们提供了动静态标准库.so/.a,这里面有方法的实现,也就是一些已经写好的二进制代码,但我们需要将我们的代码和库代码进行链接,才可以正常使用。
windows下动态库后缀为.dll静态库后缀为.lib
在安装vs2022时,我们安装的不仅仅是编译器本身,还要安装标准库的.h文件,以及标准动静态库等