关于C语言函数指针语法及动态链接库编译的技术咨询
问题1:理解
void(*func)(void)和类型转换 先拆解void(*func)(void)——这是C语言里函数指针的声明方式,咱们拆成几部分看:
*func被括号括起来,说明func本质是一个指针- 后面的
(void)表示这个指针指向的函数没有参数 - 最前面的
void表示这个函数的返回值是void类型(也就是不返回任何值)
接下来看dlsym的返回值:dlsym函数的返回类型是void*,这是C语言里的通用指针,可以指向任何数据类型,但它不能直接当成函数指针用。因为函数指针和普通数据指针在底层的表示可能存在差异(虽然很多平台上是一致的,但标准C不允许直接赋值),所以我们需要把dlsym返回的void*转换成我们需要的函数指针类型——也就是void(*)(void)。
你代码里的void (*func)(void) = dlsym(handle, "function");其实是隐式完成了这个转换,不过更标准、更安全的写法应该是显式转换:
void (*func)(void) = (void (*)(void))dlsym(handle, "function");
这样编译器就明确知道:我们把这个通用指针转换成指向“无参、无返回值函数”的指针,后续调用(*func)()的时候就能正确生成函数调用的指令了。
问题2:生成共享库文件list0513.so
你之前只做过普通.c文件的编译,生成共享库只需要给gcc加两个关键参数就行,步骤很简单:
- 打开终端,进入
list0513dl.c所在的目录 - 执行以下编译命令:
gcc -fPIC -shared list0513dl.c -o list0513.so
咱们解释下这两个核心参数:
-fPIC:生成位置无关代码(Position-Independent Code),共享库需要能被加载到内存的任意地址,所以必须用这个参数编译-shared:告诉gcc我们要生成的是共享库(.so文件),而不是普通的可执行文件
另外补充一点:编译你的主程序list0513.c的时候,需要链接dl库(因为用到了dlopen、dlsym这些动态链接相关的函数),命令是:
gcc list0513.c -o list0513 -ldl
运行的时候,如果系统找不到list0513.so,可以把当前目录加入动态库搜索路径:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./list0513
或者编译主程序的时候直接指定运行时的库路径:
gcc list0513.c -o list0513 -ldl -Wl,-rpath=.
这样运行./list0513的时候就不用手动设置环境变量了。
内容的提问来源于stack exchange,提问作者이준영
相关产品推荐
相关产品推荐

