Linux操作系统C++编程、编译控制选项、dlopen函数介绍

1. __attribute__((visibility(xxx)))的用法及功能

在Linux操作系统的gcc中的visibility属性用来控制.so文件的符号表,也就是控制外部能不能找到符号调用,比如函数、变量、模板、类等;符号表分为静态的.symtab(符号表)和动态的.dynsym,一个对应链接视图另一个对应执行视图,设置为hidden符号将不导出,即不出现在动态的.dynsym(符号表)当中,不能为模块外所使用。

-fvisibility=hidden时:

动态库中的函数默认是隐藏的,除非代码中显示声明为__attribute__((visibility(“default”)));

-fvisibility=default时:

动态库中的函数默认是可见的,除非代码中显示声明为__attribute__((visibility(“hidden”)));

总结:

-fvisibility=default|internal|hidden|protected

GCC的visibility属性,如果在编译时用到了这个属性,那么动态库的符号都是hidden的,除非进行强制声明。

在Linux下动态库(.so)中,通过GCC的C++visibility属性可以控制共享文件导出符号。

2. lambda表达式

lambda表达式(也称lambda函数)是在调用或作为函数参数传递的位置定义匿名对象的便捷方法。

通常,lambda表达式用于封装传递给算法或异步方法的几行代码。

lambda表达式语法定义:

[捕获列表] [参数列表] [可变规则/异常说明] [返回值类型] [函数体]

参数详解:

1. 捕获列表:在C++规范中也称为lambda导入器,捕获列表总是出现在lambda表达式的开始处;实际上,[]是lambda表达式的引出符,编译器根据该引出符判断接下来的代码是否是lambda表达式;捕获列表能够捕捉上下文的变量供lambda函数使用:[=]值捕获、[&]引用捕获

2. 参数列表:与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略;

3. 可变规则:mutable修饰符,默认情况下lambda函数总是一个const函数,mutable可以取消其常量性;

注意:在使用该修饰符时,参数列表不可以省略(即使参数为空)。

4. 异常说明:用于lambda表达式内部函数抛出异常。

5. 返回值类型:追踪返回形式声明函数的返回值类型,可以在不需要返回值的时候连同"->"一起省略;此外,在返回值类型明确的情况下,也可以省略该部分,让编译器对返回值类型进行推导。

6. 函数体:内容与普通函数一样,但是除了可以使用参数之外,还可以使用所有捕获的变量。

3. Getenv函数

功能:从环境中获取字符串,获取环境变量的值;

头文件:stdlib.h

函数原型:char *getenv(char *envvar);

函数说明:getenv用来取得参数envvar环境变量的内容。参数envvar为环境变量的名称,如果该变量存在则会返回指向该内容的指针。环境变量的格式为envvar=valuegetenv函数的返回值存储在一个全局二维数组里,当你再次使用getenv函数时不用担心会覆盖上次的调用结果。

返回值执行成功则返回指向该内容的指针,找不到符合的环境变量名称则返回NULL。如果变量存在但无关联值,它将运行成功并返回一个空字符串,即该字符的第一个字节是NULL

4. dlopen函数介绍

Linux操作系统提供了一套API接口来动态装载库:

C语言用户需要包含的头文件:#include<dlfcn.h>才能使用下述API接口

  • dlopen:该函数将打开一个新的动态库,并把它装入内存,该函数主要用来加载库中的符号,这些符号在编译时时不知道的。这种机制使得在系统中添加或删除一个模块时,都不需要重新进行编译;
  • dlsym:在打开的动态库中查找符号的值;
  • dlclose:关闭动态库;
  • dlerror:返回一个最后一次调用dlopen、dlsym、dlclose的错误信息的字符串。

注意:在Linux操作系统上,使用动态链接的应用程序需要和库libdl.so一起链接,也就是需要使用-ldl选项,但编译时不需要和动态装载的库一起链接!

函数原型:

l void *dlopen(const char *filename, int flag);
l char *dlsym(void *handle, const char* symbol);
l int dlclose(void *handle);
char *dlerror(void);

参数解析:重点介绍dlopen函数

filename:文件名(一个动态库.so文件);

flag:标志(指明是否立刻计算库的依赖性),如果设置为RTLD_NOW,则立刻计算,如果设置为RTLD_LAZY,则是在需要的时候才计算。另外,可以指定RTLD_GLOBA,它使得那些在以后才加载的库可以获得其中的符号。

当库被装载后,可以把dlopen函数返回的句柄作为给dlsym函数的第一个参数,以获得符号在库中的地址,使用这个地址就可以获得库中特定函数的指针,并且调用装载库中的相应函数。

在dlopne()函数以指定模式打开指定的动态库文件,并返回一个句柄给调用进程,使用dlclose()函数可以卸载打开的库。

模式的值有多个,在不同的操作系统上实现的功能有所不同,在Linux操作系统下,按照功能可以将其分为三类:

解析方式:

  • RTLD_LAZY:在dlopen函数返回前,对于动态库中的未定义的符号不执行解析(只对函数引用有效,对于变量引用总是立即解析);
  • RTLD_NOW:需要在dlopen函数返回前,解析出所有未定义符号,如果解析不出来,dlopen函数会返回NULL,报错信息:undefined symbol:xxx...

注意:如果没有指明是以上哪种模式,默认缺省为RTLD_LOCAL模式。

作用范围:(可与解析方式通过“|”符号组合使用

  • RTLD_GLOBA:动态库中定义的符号可以被其后打开的其他库重定位;
  • RTLD_LOCAL:动态库中定义的符号不能被其后打开的其他库重定位。

作用方式:

  • RTLD_NODELETE:在dlclose()期间不卸载库,并且在以后使用dlopen函数重新加载库时不初始化库中的静态变量;
  • RTLD_NOLOAD:不加载库,可用于测试库是否已经加载(dlopen()返回NULL说明库未加载,否则说明已经加载),也可以用于改变加载库的flag,如:先前加载库时flag是RTLD_LOCAL,用dlopen(RTLD_NOLOAD|RTLD_GLOBAL)后flag变成RTLD_GLOBAL;
  • RTLD_DEEPBIND:搜索全局符号前先搜索库中的符号,避免同名符号冲突。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倔强de番茄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值