源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

C语言中的强符号和弱符号介绍

  • 时间:2020-10-23 20:24 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:C语言中的强符号和弱符号介绍
之前在extern “C” 用法详解中已经提到过符号的概念,它是编译器对变量和函数的一种标记,编译器对C和C++代码在生产符号时规则也是不一样的,符号除了本身名字的区别外,还有强符号和弱符号之分 我们先看一段简单的代码
[u]复制代码[/u] 代码如下:
/* test.c */  void hello();  int main()  {      hello();      return 0;  } 
很显然,这段代码是没法链接通过的,它会报错undefined reference to hello,说的是hello未定义,因为这里我们只声明了函数hello,而没有定义它。但是我们把代码稍作修改如下
[u]复制代码[/u] 代码如下:
__attribute__((weak)) void hello();  int main()  {      hello();      return 0;  } 
这时你会发现,编译链接都可通过,但是运行会报错,因为这时我们将hello声明为了弱符号,在链接时弱符号会被链接器当做0,执行一个地址为0的函数当然会报错,改为如下代码就不会报错了,只是它没有任何输出
[u]复制代码[/u] 代码如下:
__attribute__((weak)) void hello();  int main()  {      if(hello)          hello();      return 0;  } 
编译器认为,函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号,链接器在处理强符号和弱符号时有如下规则 1.不同目标文件中,不允许有同名的强符号 2.如果一个符号在某个目标文件中是强符号,在其它目标文件中为弱符号,选择强符号 3.如果一个符号在所有目标文件中都是弱符号,选择占用空间最大的,比如目标文件A中有double global_var,文件B中有int global_var,double占用8字节,大于int的4字节,A和B链接后,符号global占8字节 对此我们可以简单的验证一下,有如下两个文件
[u]复制代码[/u] 代码如下:
/* 1.c */  char global_var;  int main()  {      return 0;  }    /* 2.c */  int global_var; 
全局变量global_var在两个文件中都没有初始化,因此都是弱符号,执行编译命令gcc 1.c 2.c,用readelf查看符号表readelf -s a.out,为了查看方便我们只输出最后几行
[u]复制代码[/u] 代码如下:
Num:    Value          Size Type    Bind   Vis      Ndx Name  62: 0000000000600818     4 OBJECT  GLOBAL DEFAULT   25 global_var  63: 0000000000400474    11 FUNC    GLOBAL DEFAULT   13 main  64: 0000000000400358     0 FUNC    GLOBAL DEFAULT   11 _init 
这里符号global_var占用的size是4,说明链接器选择的是占用空间更大的int global_var,我们再稍作修改,将1.c中的全局变量初始化,如下
[u]复制代码[/u] 代码如下:
/* 1.c */  char global_var = 1;  int main()  {      return 0;  }    /* 2.c */  int global_var; 
这时1.c中的global_var为强符号,2.c中的global_var为弱符号,同样编译之后用readelf查看符号表readelf -s a.out如下
[u]复制代码[/u] 代码如下:
Num:    Value          Size Type    Bind   Vis      Ndx Name  62: 0000000000600818     1 OBJECT  GLOBAL DEFAULT   25 global_var  63: 0000000000400474    11 FUNC    GLOBAL DEFAULT   13 main  64: 0000000000400358     0 FUNC    GLOBAL DEFAULT   11 _init 
此时符号global_var占用的size是1,说明链接器选择的是强符号 在写代码时应该尽量避免有不同类型的符号,否则会引发非常诡异且不易察觉的错误,为了避免可以采取如下措施: 1.上策:消除所有的全局变量 2.中策:将全局变量声明为static类型,并提供接口供访问 3.下策:全局变量一定要初始化,哪怕初始化为0 4.必备:打开gcc的-fno-common选项,它会禁止有不同类型的符号 说了这么多,好像在说应该尽量用强符号,那弱符号有什么用呢,所谓存在即合理,有时候我们甚至需要显示定义弱符号,这对库函数会非常有用,比如库中的弱符号可以被用户自定义的强符号覆盖,从而实现自定义的库版本,或者在使用某些扩展功能时,用户可以定义一个弱符号,当链接了该功能时,功能模块可以正常使用,如果去掉功能模块,程序也可正常链接,只是缺少某些功能而已,比如我们可以通过下面的代码判断程序是否链接了pthread库,从而决定执行什么样的操作
[u]复制代码[/u] 代码如下:
/* test.c */  #include <stdio.h>  #include <pthread.h>    __attribute__((weak)) int pthread_create(       pthread_t*,       const pthread_attr_t*,       void*(*)(void*),       void*);    int main()  {      if (pthread_create)      {          printf("This is multi-thread version!\n");      }      else      {          printf("This is single-thread version!\n");      }      return 0;  } 
编译运行结果如下
[u]复制代码[/u] 代码如下:
$ gcc test.c  $ ./a.out  This is single-thread version!  $ gcc test.c -lpthread  $ a.out  This is multi-thread version! 
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部