Linux动态链接库.so的使用方法及代码优化

如果一个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语言变量名转字符串的方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值