Linux下创建和使用共享库(动态库)
1.编译参数解析
生成动态库的三种方式
( 1)把库拷贝到/usr/lib和/lib目录下
(2)在 LD_LIBRARY_PATH 环境变量中加上库所在路径
例如动态库 libhello.so 在/home/example/lib 目录下:
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/example/lib
(3)修改/etc/ld.so.conf 文件,把库所在的路径加到文件末尾,并执行 ldconfig 刷新。这样加入的目录下的所有库文件都可见
gcc -shared -fpic libmyname.so file1.c file2.c
这样就生成里一个后缀为.so的myname的动态库文件
然后创建main.c调用库文件测试
gcc main.c libmyname.so -o main
修改库和头文件位置,编译报错
需要指定运行时搜寻的库文件目录,否则系统智慧按默认模式搜索头文件(系统标准库)
编译时使用选项-I(i)指定库名,-L指定库路径,将信息加入进去
gcc main.c -o st -libmyname.so -L ./lib -I ./inc
静态库与动态库的比较
gcc编译得到.o文件 gcc -c hello.c
创建静态库 ar -crv libmyhello.a hello.o
创建动态库 gcc -shared -fPIC -o libmyhello.so hello.o
使用库生成可执行文件 gcc -o hello main.c -L. -lmyhello
执行可执行文件 ./hello
在执行可执行文件,会报一个错误,可见当静态库和动态库同时存在的时候,程序会优先使用动态库。静态库和动态库的生成与使用其实还是比较容易的,静态库在运行可执行文件时,静态库是在可执行文件内部,即使删除静态库后程序还是能够运行,而动态库在运行可执行文件时,可执行文件需要与动态库相链接起来才能运行,所以当动态库被删除后程序无法运行,这就是静态库和动态库的区别。
下面来看看内存分配
main函数接受参数
1.int main(int argc,char *argv【】)是Linux中的标准写法,而int main()只是Linux默许的用法。
2.main函数的写法如下,c语言规定main函数的参数只能有2个,习惯上2个参数写为argc和argv。其中argc必须是整型变量,*argv【】必须是指向字符串的指针数组写法。
#include<stdio.h>
int main(int argc,char *argv[])
{
int i = 0;
for(;i<argc;i++)
{
printf("argv[%d] = %s\n",i,argv[i]);
}
return 0;
}
GDB调试工具
GDB 是 GNU 开源组织发布的一个强大的 UNIX 下的程序调试工具。也许大多数开发人员比较喜欢那种图形界面方式的,像 VC 、 BCB 等 IDE 的调试,但如果你是在 UNIX 平台下做软件开发,你会发现 GDB 这个调试工具有比 VC 、 BCB 的图形化调试器更强大的功能。所谓 “ 寸有所长,尺有所短 ” 就是这个道理。
一般来说, GDB 可以帮助你完成以下几个方面的功能:
- 启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
- 可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
- 当程序被停住时,可以检查此时你的程序中所发生的事。
- 动态的改变你程序的执行环境。
从上面看来, GDB 和一般的调试工具没有什么两样,基本上也是完成这些功能,不过在细节上,你会发现 GDB 这个调试工具的强大,大家可能比较习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。下面我们一一来看。
要使用GDB调试,需要在编译程序的时候加上-g参数,例如:
gcc -g test.c -o test
启动GDB调试test程序:
gdb test
查看源代码list或者l
#进入gdb后,并装入文件
#语法1:list line(行号)
(gdb)list #不指定行号,随机列出行号(一般为前十行)
(gdb)list 20 #显示第20行周围的内容,一般是前后各一半(总共10行内容)
#语法2:list line1,line2
(gdb)list 2,16 #显示从第2行到第16行
运行命令run或者r
#进入gdb后,并装入文件
#语法1:run
(gdb)run #运行程序
下一步next或者n
会越过函数
#进入gdb后,并装入文件
#语法1:next
(gdb)next #下一步
单独执行step或者s
会进入函数
#进入gdb后,并装入文件
(gdb)step #下一步
继续运行continue
从断点处开始,继续执行直到再次遇到断电或者结束停止
#进入gdb后,并装入文件
(gdb)continue #下一步
首行开始start
#进入gdb后,并装入文件
(gdb)start #重新开始
断点操作
1.设置断点break或者b
#语法1.指定行设置断点
#break line
(gdb)break 4
(gdb)run
#语法2.指定函数前设置断点
#break fun_name
(gdb)break add
(gdb)run
#语法3. 使用表达式设置断点(比如for循环、嵌套、递归内部变量查看)
#break line if 条件表达式
(gdb)break 8 if i=3 #当变量i的值为3时,启动第8行的断点功能
(gdb)run
(gdb)info locals #查看当前函数内的所有变量的值
显示当前gdb断点信息info break
#语法:查看当前断点信息
#info break
(gdb)info break
禁止和启用断点enable和disable
#语法:禁止断点编号
#disable breakpoints 2
(gdb)disable breakpoints 2
#语法:启用断点编号
#enable breakpoints 2
(gdb)enable breakpoints 2
删除断点delete breakpoint或者d
#语法:删除断点号n的断点
#d break n
(gdb)d break n
清除断点clear,同样达到删除断点
#语法1:清除上次停住的断点
#clear
(gdb)clear
#语法2: 清除代码行上设置的断点
#clear 行号或者是函数名
(gdb)clear n
观察点watch
#1.先设置断点
(gdb)break n
#2.先运行一下,使其生效
(gdb)run
...
#语法:条件满足时,gdb停止,前提变量必须生效一次
#watch 条件表达式
#3.设置变量观察点
(gdb)watch i=3
#4..continue继续,等待条件满足触发中断
查看变量值print或者p
#语法:显示变量的内容
#print 变量名、数组名、表达式
(gdb)print i #查看变量i的值
自动显示变量display
#语法:每次断点停止,自动显示已设置的变量的内容
#dispaly 变量名、数组名、表达式
(gdb)display i #查看变量i的值
undisplay #删除所有显示
delete display n #上次编号为n的显示,用info display可以查看
结束当前函数运行finish
(gdb)s #进入某个函数
...
#语法:finish
(gdb)finish #退出当前函数
结束当前for循环jump
最好在同一函数内junp,不能超过本函数,否则可能会出错
(gdb)s #进入某个函数
...
#语法:jump 行号
(gdb)jump n #跳到第n行
查看变量类型ptype
#语法:ptype 变量名
(gdb)ptype i #查看变量i的类型
列出当前程序存活的栈帧bt
栈帧:随着函数调用而在stack上开辟的一片内存空间。用于存放函数调用时产生的局部变量和临时值。
根据栈帧编号,切换栈帧frame
(gdb)s #进入某函数
#语法:bt
(gdb)bt #显示当前存活的栈帧
#语法:frame n #根据显示存活的栈帧编号n,切换到栈帧n
(gdb)frame 0