一,c语言程序在linux系统的使用
在Linux中我们没有类似vs2022和vscode之类的编译器,我们使用的是gcc去编译我们的代码
1,gcc分步编译链接
(1) 预编译 : gcc -E main.c -o main.i
(2) 编译: gcc -S main.i -o main.s
(3) 汇编: gcc -c main.s -o main.o
(4) 链接: gcc main.o -o main
gcc的一步编译通常使用gcc test.c -o main
2,编译链接过程
所以的c语言程序都会经过预编译,编译,汇编,链接四个步骤,从而将文本文件转化成可执行程序。
3,预编译阶段
a) 删除所有的“#define”,并且展开所有的宏定义;
b) 处理所有的条件预编译指令,“#if”、“#ifdef”、“#endif”等;
c) 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置;
d) 删除所有的注释;
e) 添加行号和文件名标识,以便于编译器产生调试用的符号信息及编译时产生编译错 误和警告时显示行号;
f) 保留所有的#pragma 编译器指令,因为编译器需要使用它们。
3.2 编译阶段
词法分析、语法分析、语义分析,代码优化,汇总符号。
3.3 汇编阶段
将汇编指令翻译成二进制格式,生成各个 section,生成符号表。
3.4 链接阶段
a) 合并各个 section,调整 section 的起始位移和段大小,合并符号表,进行符号解析, 给符号分配虚拟地址
b) 符号重定位
4、makefile 和 make
在linux中如果有多个文件需要编译,一个个去编译是很麻烦的,所以我们可以去使用make命令一部编译,具体操作如下
对 main.c add.c max.c 三个文件进行编译(注意: gcc 前面必须是 table 建缩进)
clean是为了删除多余的不必要文件。
make 命令根据 makefile 文件的规则生成可执行程序
5、gdb 调试
5.1 Debug 版本和 Release 版本
Debug 版本
Debug 版本为可调式版本,生成的可执行文件中包含调试需要的信息。我们作为开发人 员,最常用的就是 debug 版本的可执行文件。
Debug 版本的生成:
因为调试信息是在编译过程时加入到中间文件(.o)中的,所以必须在编译时控制其生 成包含调试信息的中间文件。
gcc -o hello hello.c -g
Release 版本
Release 版本为发行版本,是提供给用户使用的版本。用 gcc 默认生成的就是 Release 版本。
首先将源代码编译、链接生成 Debug 版本的可执行文件,然后通过‘gdb Debug 版本 的可执行文件名’进入调试模式。
5.2 单进程、单线程基础调试命令
二,库文件
1、什么是库文件
库是一组预先编译好的方法的集合。
Linux系统存储的库的位置一般在:/lib 和 /usr/lib。
在 64 位的系统上有些库也可能被存储在/usr/lib64 下。库的头文件一般会被存储在 /usr/include 下或其子目录下。
库有两种,一种是静态库,其命令规则为 libxxx.a,一种是共享库,其命令规则为 libxxx.so。
2、静态库的生成与使用
2.1 静态库的生成
以下是需要生成静态库的”.c”文件,其中“foo.h”中是函数的声明,“add.c”和“max.c” 是函数的定义
第一步:先将需要生成库文件的所有“.c“文件编译成“.o”文件
第二步:使用 ar 命令将第一步编译的所有”.o”文件生成静态库,其中: ◼ c 是创建库 ◼ r 是将方法添加到库中 ◼ v 显示过程
2.2 静态库的使用
以下是测试代码”main.c”中的内容:
以下是使用静态库“libfoo.a”和“main.c”生成可执行文件的过程,其中:
◼ -L 指定库的存储路径
◼ -l 指定库的名称(不需要前面的‘lib’和扩展名‘.a’)
3、共享库的生成与使用
3.1 共享库的生成
以下是需要生成共享库的”.c”文件,其中“foo.h”中是函数的声明,“add.c”和“max.c” 是函数的定义
第一步:先将需要生成库文件的所有“.c“文件编译成“.o”文件
第二步:使用 gcc 命令将第一步编译的所有”.o”文件生成共享库
3.2 共享库的使用
以下是测试代码”main.c”中的内容:
以下是使用共享库“libfoo.so”和“main.c”生成可执行文件的过程,其中 -L 指定库的 存储路径, -l 指定库的名称(不需要前面的‘lib’和扩展名‘.so’), 如果在库的存储路径 有同名的共享库和静态库,gcc 默认使用共享库。
生成之后,直接执行 main 程序,发现出错,原因是系统加载共享库时,找不到对应的 共享库文件”libfoo.so”, 但是该库确实在当前目录下存在。这是为什么呢?因为系统默认 只会去存储库的标准位置(/lib 或/usr/lib 等)加载,而不会在当前位置寻找。所以将库拷贝到 /usr/lib 下,再执行程序,就可以成功。 如果库不在标准位置下,也可以通过设置环境变量”LD_LIBRARY_PATH”来指定加 载库的路径。
4、静态库和共享库的区别
静态库在链接时将用到的方法包含到最终生成的可执行程序中,而共享库不包含,只做 标记,在运行程序时,才动态加载