如果一个api.so中包含一个名为api_aaa的函数:
int api_aaa(int param_1);
调用过程如下:
int main()
{
int (*api_aaa)(int param_1) = NULL;
void *handle = NULL;
handle = dlopen("xxx/xxx/api.so", RTLD_LAZY);
if(!handle) {
printf("can't load file\n");
return -1;
}
api_aaa = dlsym(handle, "api_aaa");
if(!api_aaa) {
printf("can't load function: api_aaa\n");
}
else
api_aaa(123);
dlclose(handle);
}
在实际使用过程中一个库通常会包含多个函数,获取函数地址的代码可能是这样的:
api_aaa = dlsym(handle, "api_aaa");
if(!api_aaa) {
printf("can't load function: api_aaa\n");
}
api_bbb= dlsym(handle, "api_bbb");
if(!api_bbb) {
printf("can't load function: api_bbb\n");
}
...
api_yyy= dlsym(handle, "api_aaa");
if(!api_yyy) {
printf("can't load function: api_yyy\n");
}
api_zzz= dlsym(handle, "api_zzz");
if(!api_aaa) {
printf("can't load function: api_zzz\n");
}
有没有注意到最后两次调用有什么问题?第13和19行都使用了错误的api_aaa。
对于重复的代码我们通常都是复制、粘贴,然后再修改有差异的地方,而这段代码每次要修改4处,一不小心就会有遗漏。
在写程序时应该尽量避免挖这样的坑,灵活运用之前一篇文章讲到的将变量名转换成字符串的方法可以避免这样的问题。
const char api_path[] = "xxx/xxx/api.so";
int (*api_aaa)(int param_1) = NULL;
int (*api_bbb)(short param_1) = NULL;
int (*api_ccc)(int param_1, char param_2) = NULL;
static void *drv_handle = NULL;
#define func_name(x) ((void **)&x),(#x)
int get_func(void *handle, void ** func, char *func_name)
{
*func = dlsym(handle, func_name);
if(!*func) {
printf("can't load function: %s\n", func_name);
return 1;
}
return 0;
}
static int get_hal_funcs(void *handle)
{
int error = 0;
error += get_func(handle, func_name(api_aaa));
error += get_func(handle, func_name(api_bbb));
error += get_func(handle, func_name(api_ccc));
return error;
}
int api_load(void)
{
int err;
printf("Welcome to visit http://blog.csdn.net/veabol\n");
drv_handle = dlopen(api_path, RTLD_LAZY);
if(drv_handle == NULL) {
printf("can't open %s", api_path);
return -1;
}
err = get_hal_funcs(drv_handle);
if(err) {
printf("~~~~~~%d functions failed\n", err);
return err;
}
return 0;
}
int api_release(void)
{
if(drv_handle) {
dlclose(drv_handle);
drv_handle = NULL;
}
return 0;
}
使用以上代码后,只需要在复制、粘贴后修改get_func(handle, func_name(api_aaa))中的一个参数就可以了,有效避免错误的出现,其中主要是用到了变量名转字符串的方法。
#define func_name(x) ((void **)&x),(#x)
可以参考我之前的文章:C语言变量名转字符串的方法