visibility
__attribute__((visibility("visibility_type")))
当我们并不希望暴露一个方法时,一般情况使用static
关键字来修饰函数。这样编译时该方法就不会被输出到符号表里。详细可参见这篇博文
LLVM和GCC其实也提供了类似的attribute
使用示例:
__attribute__((visibility("default"))) void foo1(int x, int y);
__attribute__((visibility("hidden"))) int foo2(int x);
__attribute__((visibility("protected"))) void foo3(int x, int y);
default
意味着该方法对其他模块是可见的。而
hidden
表明该方法符号不会被放到动态符号表里,所以其他模块(可执行文件或者动态库)不可以通过符号表访问该方法。(但在运行时使用函数指针可对其进行调用,visibility是个编译时的特性,正如你在运行时可以修改const修饰的变量一样)protected
则表示该方法将会被放置到动态符号表,对其他模块可见。但该符号对其所在模块是绑定的,即其他模块不可重载该符号。internal
,跟hidden
相似。除非特别指定,否则意味着不能从模块调用该方法。
-fvisibility
既然说到了visibility,那顺带说一下这个flag,这个flag在调用gcc或者llvm时指定。表示编译时的对所有方法的默认visibility的选择(除非显式指定方法的visibility)。
-fvisibility=default|internal|hidden|protected
一般来说隐藏方法使用static
就够了。但此attribute为大型工程项目提供了一种可能性,即可以使某些模块整体隐藏所有接口,只暴露特别指定的方法。
其他
此外gcc的编译器还可以像如下这样使用:
#pragma GCC visibility push(hidden)
void method1() {...}
void method2() {...}
...
#pragma GCC visibility pop
即表示在push
与pop
之间声明的所有方法,其可见性都按照指定的进行编译。
private_extern
这个关键字也有static相同的作用
总述
通过上述提供的几种手段,在一些复杂模块化的大中型项目中,我们可以更加灵活地对不同模块进行可行性的控制,能够更精细对项目进行模块化,并且减少符号被覆盖的风险。
还有一些有趣的attribute,以后再写
objc_root_class
objc_designated_initializer
naked
原作写于segmentfault 链接