服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C语言中的强符号和弱符号介绍

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

2021-02-23 11:38C语言教程网 C/C++

这篇文章主要介绍了C语言中的强符号和弱符号介绍,本文用多个实例来讲解强符号和弱符号,需要的朋友可以参考下

之前在extern “C” 用法详解中已经提到过符号的概念,它是编译器对变量和函数的一种标记,编译器对C和C++代码在生产符号时规则也是不一样的,符号除了本身名字的区别外,还有强符号和弱符号之分

我们先看一段简单的代码

复制代码 代码如下:

/* test.c */ 
void hello(); 
int main() 

    hello(); 
    return 0; 


很显然,这段代码是没法链接通过的,它会报错undefined reference to hello,说的是hello未定义,因为这里我们只声明了函数hello,而没有定义它。但是我们把代码稍作修改如下

复制代码 代码如下:

__attribute__((weak)) void hello(); 
int main() 

    hello(); 
    return 0; 


这时你会发现,编译链接都可通过,但是运行会报错,因为这时我们将hello声明为了弱符号,在链接时弱符号会被链接器当做0,执行一个地址为0的函数当然会报错,改为如下代码就不会报错了,只是它没有任何输出

复制代码 代码如下:

__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字节

对此我们可以简单的验证一下,有如下两个文件

复制代码 代码如下:

/* 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,为了查看方便我们只输出最后几行

复制代码 代码如下:

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中的全局变量初始化,如下

复制代码 代码如下:

/* 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如下

复制代码 代码如下:

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库,从而决定执行什么样的操作

复制代码 代码如下:

/* 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; 

 

编译运行结果如下

复制代码 代码如下:

$ gcc test.c 
$ ./a.out 
This is single-thread version! 
$ gcc test.c -lpthread 
$ a.out 
This is multi-thread version! 

延伸 · 阅读

精彩推荐
  • C/C++使用C++制作简单的web服务器(续)

    使用C++制作简单的web服务器(续)

    本文承接上文《使用C++制作简单的web服务器》,把web服务器做的功能稍微强大些,主要增加的功能是从文件中读取网页并返回给客户端,而不是把网页代码...

    C++教程网5492021-02-22
  • C/C++深入C++拷贝构造函数的总结详解

    深入C++拷贝构造函数的总结详解

    本篇文章是对C++中拷贝构造函数进行了总结与介绍。需要的朋友参考下...

    C++教程网5182020-11-30
  • C/C++关于C语言中E-R图的详解

    关于C语言中E-R图的详解

    今天小编就为大家分享一篇关于关于C语言中E-R图的详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看...

    Struggler095962021-07-12
  • C/C++c/c++内存分配大小实例讲解

    c/c++内存分配大小实例讲解

    在本篇文章里小编给大家整理了一篇关于c/c++内存分配大小实例讲解内容,有需要的朋友们可以跟着学习参考下。...

    jihite5172022-02-22
  • C/C++OpenCV实现拼接图像的简单方法

    OpenCV实现拼接图像的简单方法

    这篇文章主要为大家详细介绍了OpenCV实现拼接图像的简单方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    iteye_183805102021-07-29
  • C/C++C语言main函数的三种形式实例详解

    C语言main函数的三种形式实例详解

    这篇文章主要介绍了 C语言main函数的三种形式实例详解的相关资料,需要的朋友可以参考下...

    ieearth6912021-05-16
  • C/C++c/c++实现获取域名的IP地址

    c/c++实现获取域名的IP地址

    本文给大家汇总介绍了使用c/c++实现获取域名的IP地址的几种方法以及这些方法的核心函数gethostbyname的详细用法,非常的实用,有需要的小伙伴可以参考下...

    C++教程网10262021-03-16
  • C/C++C语言实现双人五子棋游戏

    C语言实现双人五子棋游戏

    这篇文章主要为大家详细介绍了C语言实现双人五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    两片空白7312021-11-12