函数导出可视问题
最近从深圳裸辞回到了长沙,要忙的事情太多,当然,最主要的还是找工作的事情。长沙这边可投的公司实在是太少,但幸运的是,有不少同学和朋友的帮忙,而几个岗位的面试也都是十分的顺利,嘛,厚积薄发,继续努力,所以,来看本文主题:C语言里的函数导出可视问题。
这源于前几天去一家公司面试时做的一个试题,我们知道C语言里有一个很给力的关键字static,既可以修饰变量,也可以修饰函数。关于static的作用,在网上有很多描述,见参考1,2。这里重点关注的是:如果函数没有被static修饰,那么它就是全局可见的,而这对于创建动态共享库会带来一些麻烦,因为那些没有被static修饰的函数在默认情况下都成了导出函数。如果一个工程链接了多个动态共享库,而部分库又存在相同的函数名称时,也许我们链接使用的函数就不是原本期待的那个。之前在项目中就遇到过好几次这样的情况,如果参数不一致还好,因为能够在编译时就得到告警提示,从而及时解决,否则就需在实际执行时才发现程序行为异常,再做问题定位就稍显麻烦些了。
看实例:
lenky@lenky-virtual-machine:~/work$ cat foo.c int foo() { return 11; } int bar() { return 12; } lenky@lenky-virtual-machine:~/work$ cat bar.c int foo() { return 21; } int bar() { return 22; } lenky@lenky-virtual-machine:~/work$ gcc -shared -fPIC -o libfoo.so foo.c lenky@lenky-virtual-machine:~/work$ gcc -shared -fPIC -o libbar.so bar.c
上面准备了两个动态库,分别为libfoo.so和libbar.so,它们都包含有函数foo()和bar(),没有被static修饰,默认也就是导出函数。
一个名为test.c的程序需要使用共享库libfoo.so内的函数foo()以及libbar.so内的bar()函数:
lenky@lenky-virtual-machine:~/work$ cat test.c #include <stdio.h> int main() { printf("foo-11:%d\n", foo()); printf("bar-22:%d\n", bar()); return 0; }
编译并执行:
lenky@lenky-virtual-machine:~/work$ gcc test.c -o test -lfoo -lbar /usr/bin/ld: cannot find -lfoo /usr/bin/ld: cannot find -lbar collect2: error: ld returned 1 exit status lenky@lenky-virtual-machine:~/work$ export LIBRARY_PATH=. lenky@lenky-virtual-machine:~/work$ gcc test.c -o test -lfoo -lbar lenky@lenky-virtual-machine:~/work$ ./test ./test: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory lenky@lenky-virtual-machine:~/work$ export LD_LIBRARY_PATH=. lenky@lenky-virtual-machine:~/work$ ./test foo-11:11 bar-22:12
打印结果表明调用的bar()函数并不是来自libbar.so共享库。调换一下链接库的先后顺序,发现调用的foo()函数不是来自libfoo.so共享库:
lenky@lenky-virtual-machine:~/work$ gcc test.c -o test -lbar -lfoo lenky@lenky-virtual-machine:~/work$ ./test foo-11:21 bar-22:22
因此,我们需要做隐藏,比如这样:
lenky@lenky-virtual-machine:~/work$ cat foo.c int foo() { return 11; } static int bar() { return 12; } lenky@lenky-virtual-machine:~/work$ cat bar.c static int foo() { return 21; } int bar() { return 22; } lenky@lenky-virtual-machine:~/work$ gcc -shared -fPIC -o libfoo.so foo.c lenky@lenky-virtual-machine:~/work$ gcc -shared -fPIC -o libbar.so bar.c lenky@lenky-virtual-machine:~/work$ gcc test.c -o test -lbar -lfoo lenky@lenky-virtual-machine:~/work$ ./test foo-11:11 bar-22:22
利用static关键字帮助我们达到了既定目的,但是static限制了其修饰的函数只能在对应的源文件内使用。因此,如果还想在共享库的多个源文件内共享一个函数,static就不可用了。所幸,强大的gcc扩展为此提供了一个选项__attribute__((visibility(“hidden”)))。如此以来,上面的static修饰可以改为这样:
lenky@lenky-virtual-machine:~/work$ cat foo.c
int foo() {
return 11;
}
__attribute__((visibility("hidden")) int bar() {
return 12;
}
lenky@lenky-virtual-machine:~/work$ cat bar.c
__attribute__((visibility("hidden"))) int foo() {
return 21;
}
int bar() {
return 22;
}
lenky@lenky-virtual-machine:~/work$ gcc -shared -fPIC -o libbar.so bar.c
lenky@lenky-virtual-machine:~/work$ gcc -shared -fPIC -o libbar.so bar.c
lenky@lenky-virtual-machine:~/work$ gcc test.c -o test -lbar -lfoo
lenky@lenky-virtual-machine:~/work$ ./test
foo-11:11
bar-21:22
与此相对的一个选项是__attribute__((visibility(“default”))),可以认为它是用于明确表示该符号不被隐藏。给想被导出的函数加上default可视,给不想被导出的函数加上hidden隐藏,就可以避免直接使用static关键字而带来的不便。
参考:
1,http://www.cnblogs.com/dc10101/archive/2007/08/22/865556.html
2,http://blog.163.com/sunshine_linting/blog/static/4489332320119785228616/
转载请保留地址:http://lenky.info/archives/2013/05/25/2289 或 http://lenky.info/?p=2289
备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。
法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以或书面等方式告知,本站将及时删除相关内容或链接。
除了代码中用编译选项__attribute__ ((visibility(“hidden”)))外,还可以用形如
bash$ cat vis.map
VER_1 {
global:
vis_f1;
vis_f2;
local:
*;
};
的脚本来配置动态库函数服务作用域,其中vis_f1 vis_f2在动态库外部可见,
用形如 gcc -g -shared -o vis.so vis_comm.o vis_f1.o vis_f2.o \
-Wl,–version-script,vis.map
编译选项编译动态库。
很清楚static的作用。不过gcc的扩展还是非常强大的。
没看出有什么好处,一样要改代码
你好,跟你是老乡 也算湖南人
你会长沙发展了?据我所知长沙没看到有互联网公司啊