(七)gdb调试 及静态库共享库

发布时间:2026/8/16 1:56:03
(七)gdb调试 及静态库共享库 一、gdb 常用调试命令前提编译程序必须加-g参数加入调试信息gcc main.c -g -o main否则 gdb 看不到源码。命令作用l/l 行号list显示源码l 10直接跳到第 10 行附近显示代码b 行号/b 函数名break设置断点b 20/b addinfo break查看所有断点信息显示断点编号delete 断点编号删除指定断点delete不加编号删除全部断点rrun从头运行程序遇到断点停下nnext单步执行不进入函数越过函数sstep单步执行进入调用的函数内部finish执行完当前函数跳出函数返回到调用处ccontinue继续运行直到下一个断点p 变量名print打印变量 / 表达式的值p abtbacktrace打印完整函数调用栈bt n只打印前 n 层调用栈qquit退出 gdb小提示gdb 敲回车会重复执行上一条命令。二、C 库基础头文件stdio.h——函数声明告诉编译器函数长什么样 库文件/usr/lib/libc.so.6——函数实现已经编译好的机器码集合。.h只放声明没有实现代码库文件存放真正编译完成的二进制实现代码库分为两大类静态库.a、共享 (动态) 库.so1、静态库.a本质多个.o目标文件归档打包而成使用ar工具制作。ar 参数c创建库文件r把目标文件添加进库vverbose显示操作过程生成静态库示例# 1.先把源码编译成目标文件 .o gcc -c add.c -o add.o gcc -c max.c -o max.o # 2.打包生成静态库 libfoo.a ar crv libfoo.a add.o max.o使用静态库链接生成可执行程序gcc main.o -L. -lfoo -o app-L.指定库搜索路径.代表当前目录-lfoo代表库名libfoo.a去掉lib前缀和.a后缀⚠️ 注意同一个目录下同时存在libfoo.a(静态) 和libfoo.so(动态)gcc优先链接动态库。静态库优缺点✅优点 链接阶段把库代码完整复制进可执行文件运行时不再依赖原库文件删掉libfoo.a程序照样跑。❌缺点可执行文件体积大每份程序都拷贝一份库代码内存浪费静态库更新后所有使用该库的程序必须重新编译链接才能用上新版本。2、共享库动态库.so运行的时候才加载库到内存多个进程可以共用内存里同一份库代码。编译生成动态库示例# -fPIC 生成位置无关代码动态库必备参数 gcc -c -fPIC add.c -o add.o gcc -c -fPIC max.c -o max.o # 生成共享库 libfoo.so gcc -shared add.o max.o -o libfoo.so链接使用动态库gcc main.o -L. -lfoo -o app动态库优缺点✅优点多个程序共享内存中一份库代码节省内存更新.so库文件只要接口不变程序不需要重新编译重启程序就使用新版库。❌缺点 运行依赖.so文件如果库丢失、版本不匹配程序直接运行失败。编译小技巧gcc 可以一步编译不需要手动生成.o# 直接用c源码链接静态库 gcc main.c -L. -lfoo -o appLD_LIBRARY_PATH 环境变量动态库运行时搜索路径。 gcc 编译时通过-L找库程序运行时不会读取 - L 参数操作系统会去系统库目录和LD_LIBRARY_PATH环境变量指定目录寻找.so。# 设置临时环境变量当前终端生效 export LD_LIBRARY_PATH.:$LD_LIBRARY_PATH ./app补充编译器默认自动链接 libc 标准库数学库libm需要手动加-lm。补充对比小结项目静态库.a动态共享库.so链接时机编译链接阶段拷贝代码编译只记录引用运行时加载运行依赖不依赖原库文件必须存在对应 so 文件内存占用每个程序自带一份库代码占用大多进程共享内存一份库库更新程序需要重新编译链接接口兼容时无需重编译制作工具argcc -shared