您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > C/C++/C#

C语言的强符号,弱符号以及它们的用途

时间:2020-04-08 11:17:26  来源:  作者:

引言

虽然用C语言这么多年,但强符号,弱符号这类东西没有多大关注,最近关注到,感觉挺实用的。

什么是强符号,弱符号

大家都知道,我们的程序里,不论是变量名,还是函数名,都是符号,它存在于编译链接整个过程,甚至在最终的可执行文件中也有(一般用于程序调试),是各目标文件之间的"粘合剂",符号贯穿了我们的程序从无到有的整个过程。

我们在编译代码的过程中,经常会碰到类似这样错误:

C语言的强符号,弱符号以及它们的用途

 

其实这就是因为链接目标文件的过程中,链接器遇到了两个强符号,而同时存在两个相同的强符号,会导致链接器不知道应该选哪一个,所以就直接报错。

那么怎么样的才算强符号,怎么样的才算弱符号呢?

正式开始前,先来了解一下GCC的attribute特性里支持weak属性,这个和符号的强弱有直接关系,关于该属性,GNU的官方定义如下:

The weak attribute causes a declaration of an external symbol to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions that can be overridden in user code, though it can also be used with non-function declarations. The overriding symbol must have the same type as the weak symbol. In addition, if it designates a variable it must also have the same size and alignment as the weak symbol. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.

大概的意思就是,weak属性可以将一个符号声明为弱符号,可以用于函数库中,方便用户定义自己的符号以覆盖库中的符号。

先来看看全局变量的强符号与弱符号,看下下面几个测试用例。按如下方式,生成文件test.c:

#include <stdio.h>

int tc_0;
int tc_0 = 6;
int __attribute__((weak)) tc_0;
int __attribute__((weak)) tc_0=1;

int main(void)
{
    printf("tc_0:%drn",tc_0);
    return 0;
}

编译产生如下错误:

C语言的强符号,弱符号以及它们的用途

 

看来,即便变量定义的时候,赋了weak属性,但是变量初始化了,也会被认为是强符号,尝试将"int __attribute__((weak)) tc_0=1;"这一行定义注释掉:

#include <stdio.h>

int tc_0;
int tc_0 = 6;
int __attribute__((weak)) tc_0;
//int __attribute__((weak)) tc_0=1;

int main(void)
{
    printf("tc_0:%drn",tc_0);
    return 0;
}

编译通过了,执行结果如下:

C语言的强符号,弱符号以及它们的用途

 

这里可以得出,没有初始化的全局变量为弱符号,而初始化过的全局变量为强符号。但是对于赋了weak属性又初始化过的变量,虽然在同一个文件里和初始化过的全局变量同样表现为强符号,但是如果定义在不同的文件里会是什么情况呢?这一点需要确认清楚。因此,再建立文件test2.c:

#include <stdio.h>

int __attribute__((weak)) tc_0 = 1;

此时和前面的现象不同,同样可以编译通过。执行结果和上一次一样,符合预期,因为test2.c的变量被添加了weak属性:

C语言的强符号,弱符号以及它们的用途

 

将两个文件里的全局变量强弱属性交换一下,再次验证:

test.c:

#include <stdio.h>

int tc_0;
int __attribute__((weak)) tc_0 = 6;
int __attribute__((weak)) tc_0;

int main(void)
{
    printf("tc_0:%drn",tc_0);
    return 0;
}

test2.c

#include <stdio.h>

int tc_0 = 1;

编译执行结果如下:

C语言的强符号,弱符号以及它们的用途

 

可以确定,在不同的文件中,符号的强弱关系和weak属性强相关,不存在模糊地带,一般的应用或者容易出问题的地方也都是在不同的文件之间。

了解完全局变量,再来了解一下函数。如果直接两个文件有完全一样的函数,肯定会报定义冲突,就不再讨论,主要来看看将其中一个函数添加weak属性的情况

test.c:

#include <stdio.h>

void __attribute__((weak)) tc_0(void)
{
    printf("tc_o in test.crn");
    return;
}

int main(void)
{
    tc_0();
    return 0;
}

test2.c

#include <stdio.h>

void tc_0(void)
{
    printf("tc_o in test2.crn");
    return;
}

编译执行后,结果如下:

C语言的强符号,弱符号以及它们的用途

 

可见,可以编译通过,且main函数里实际调用的是test2.c里的函数。

强符号,弱符号有何用处

那么这个有什么用呢?其实在GNU的定义里已经提到了,强弱符号最大的用处在于,设计框架代码或函数库的时候,可以将默认接口或变量定义弱符号,用户可在自己的代码里定义自己的接口或变量,这样编译链接的时候链接器会链接用户自己定义的接口或变量。这样可以增加框架或函数库的弹性,更方便满足用户自定义的需求。



Tags:C语言 强符号   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
引言虽然用C语言这么多年,但强符号,弱符号这类东西没有多大关注,最近关注到,感觉挺实用的。什么是强符号,弱符号大家都知道,我们的程序里,不论是变量名,还是函数名,都是符号,它存在于...【详细内容】
2020-04-08  Tags: C语言 强符号  点击:(112)  评论:(0)  加入收藏
▌简易百科推荐
一、简介很多时候我们都需要用到一些验证的方法,有时候需要用正则表达式校验数据时,往往需要到网上找很久,结果找到的还不是很符合自己想要的。所以我把自己整理的校验帮助类分...【详细内容】
2021-12-27  中年农码工    Tags:C#   点击:(2)  评论:(0)  加入收藏
引言在学习C语言或者其他编程语言的时候,我们编写的一个程序代码,基本都是在屏幕上打印出 hello world ,开始步入编程世(深)界(坑)的。C 语言版本的 hello world 代码:#include <std...【详细内容】
2021-12-21  一起学嵌入式    Tags:C 语言   点击:(11)  评论:(0)  加入收藏
读取SQLite数据库,就是读取一个路径\\192.168.100.**\position\db.sqlite下的文件<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/...【详细内容】
2021-12-16  今朝我的奋斗    Tags:c#   点击:(21)  评论:(0)  加入收藏
什么是shellshell是c语言编写的程序,它在用户和操作系统之间架起了一座桥梁,用户可以通过这个桥梁访问操作系统内核服务。 它既是一种命令语言,同时也是一种程序设计语言,你可以...【详细内容】
2021-12-16  梦回故里归来    Tags:shell脚本   点击:(18)  评论:(0)  加入收藏
一、编程语言1.根据熟悉的语言,谈谈两种语言的区别?主要浅谈下C/C++和PHP语言的区别:1)PHP弱类型语言,一种脚本语言,对数据的类型不要求过多,较多的应用于Web应用开发,现在好多互...【详细内容】
2021-12-15  linux上的码农    Tags:c/c++   点击:(17)  评论:(0)  加入收藏
1.字符串数组+初始化char s1[]="array"; //字符数组char s2[6]="array"; //数组长度=字符串长度+1,因为字符串末尾会自动添&lsquo;\0&lsquo;printf("%s,%c\n",s1,s2[2]);...【详细内容】
2021-12-08  灯-灯灯    Tags:C语言   点击:(47)  评论:(0)  加入收藏
函数调用约定(Calling Convention),是一个重要的基础概念,用来规定调用者和被调用者是如何传递参数的,既调用者如何将参数按照什么样的规范传递给被调用者。在参数传递中,有两个很...【详细内容】
2021-11-30  小智雅汇    Tags:函数   点击:(19)  评论:(0)  加入收藏
一、问题提出问题:把m个苹果放入n个盘子中,允许有的盘子为空,共有多少种方法?注:5,1,1和1 5 1属同一种方法m,n均小于10二、算法分析设f(m,n) 为m个苹果,n个盘子的放法数目,则先对...【详细内容】
2021-11-17  C语言编程    Tags:C语言   点击:(49)  评论:(0)  加入收藏
一、为什么需要使用内存池在C/C++中我们通常使用malloc,free或new,delete来动态分配内存。一方面,因为这些函数涉及到了系统调用,所以频繁的调用必然会导致程序性能的损耗;另一...【详细内容】
2021-11-17  深度Linux    Tags:C++   点击:(38)  评论:(0)  加入收藏
OpenCV(Open Source Computer Vision Library)是一个(开源免费)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android、ios等操作系统上,它轻量级而且高效---由一系列...【详细内容】
2021-11-11  zls315    Tags:C#   点击:(50)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条