GCC: __attribute__((visibility()))

objc-api.h 里面有很多关于 __attribute__ 的定义。

例如下面的代码片段:

1
2
3
4
5
6
7
8
9
10
11
#if !defined(OBJC_VISIBLE)
# if TARGET_OS_WIN32
# if defined(BUILDING_OBJC)
# define OBJC_VISIBLE __declspec(dllexport)
# else
# define OBJC_VISIBLE __declspec(dllimport)
# endif
# else
# define OBJC_VISIBLE __attribute__((visibility("default")))
# endif
#endif

可以看到:OBJC_VISIBLE 的定义方式是 __attribute__((visibility("default")))

那么究竟有什么作用呢?下面举例说明。


GCC 有个 visibility 属性,启用这个属性情况如下说明。

1、当编译时增加 -fvisibility=hidden

动态库中的函数默认是被隐藏的即 hidden,除非显示声明为 __attribute__((visibility("default")))

2、当编译时增加 -fvisibility=default

动态库中的函数默认是可见的。除非显示声明为 __attribute__((visibility("hidden")))

特别说明::这个特性是 GCC4.0 以后才有的。

基于 GCC系列: 加载静态链接库 的例子。谈谈 visibility。

Car.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<stdio.h>
#include<stdlib.h>
__attribute ((visibility("default"))) int drive()
{
printf("Car driving...\n");
return 0;
}
void stop()
{
printf("Car stop.\n");
}

注意:attribute 的定义和使用方法

使用 visibility 属性来编译动态链接库,如下:

1
g++-4.9 -shared -o libCar.so -fvisibility=hidden Car.c

这样一来,drive 方法是可见的,但是 stop 是不可见的。

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<stdio.h>
#include<stdlib.h>
//
// 在 gcc 编译器下, 必须声明方法
// 在 clang 编译下, 只是给了警告
//
int drive();
void stop();
int main()
{
drive();
stop();
return 0;
}

编译

1
g++-4.9 -o app main.c -L ./ -lCar

提示信息

1
2
3
4
5
Undefined symbols for architecture x86_64:
"stop()", referenced from:
_main in ccZnwENu.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

这说明了上面提到的第一种情况。

重新编译 Car.c,换个方式:

1
g++-4.9 -shared -o libCar.so -fvisibility=default Car.c

注意: 这次使用了 default 属性。

编译 main.c

1
g++-4.9 -o app main.c -L ./ -lCar

编译成功,运行程序

1
2
3
./app
Car driving...
Car stop.

那么修改一下 Car.c 的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<stdio.h>
#include<stdlib.h>
__attribute ((visibility("default"))) int drive()
{
printf("Car driving...\n");
return 0;
}
__attribute ((visibility("hidden"))) void stop()
{
printf("Car stop.\n");
}

使用 visibility=defaultvisibility=hidden 分别编译 Car.c.

可以知道,stop 函数都是隐藏的,这个也很好的说明了上面两个问题。

另外,除了 defaulthidden,还有 internalprotected 等,大家可以根据自己的使用场景选择使用即可。


选择比努力更重要,将就可以一时但不能一世~

坚持原创技术分享!