千家信息网

C语言中弱符号与弱引用怎么用

发表于:2024-10-19 作者:千家信息网编辑
千家信息网最后更新 2024年10月19日,这篇文章将为大家详细讲解有关C语言中弱符号与弱引用怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。符号重定义错误在编码过程中,我们经常遇到符号重定义的错误。编译
千家信息网最后更新 2024年10月19日C语言中弱符号与弱引用怎么用

这篇文章将为大家详细讲解有关C语言中弱符号与弱引用怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

符号重定义错误

在编码过程中,我们经常遇到符号重定义的错误。编译器会报如下错误:

multiple definition of `xxx';

这就是符号重复定义导致的,再往细里面说,是在同一作用域内符号冲突。我们知道变量是由作用域生命周期概念的。比如:

例1:main.cint strong=0;int main(){        printf("strong = %d\n",strong);        return 0;}strong.cint strong=1;

gcc main.c strong.c -o main 则会报重定义错误。因为在main.c 和strong.c 文件中,整型变量strong是全局变量,它们的作用域都是跨文件的。若是在不同的作用域,即使相同变量名,也不会报错编译器会有默认的优先级处理:总是更小作用域的变量覆盖更大作用域的变量,前提是这两个变量的作用域是包含或被包含的关系。比如:

例2:main.cint strong=0;int main(){        printf("strong = %d\n",strong);        return 0;}strong.cstatic int strong=1;

gcc main.c strong.c -o main 不再报错。此时main.c 中的strong 变量的作用域是跨文件,而strong.c中的strong变量的作用域仅限strong.c文件。因此不存在相同作用域中,符号重定义问题。并且结果输出为0;
同理,下面的代码会编译报错吗?输出为多少呢?

main.cint strong=0;int main(){        int strong=2;        printf("strong = %d\n",strong);        return 0;}strong.cstatic int strong=1;

甚至于下面的代码也是合法的:

main.cint strong=0;int main(){        int strong=2;        if(1)        {                int strong=3;        }        {                       int strong = 4;                printf("strong = %d\n",strong);        }        return 0;}

在C语言中,我们可以简单地认为花括号是文件内作用域的分隔符。

强符号与弱符号

编译器默认函数和已初始化的全局变量为强符号,而未初始化的全局变量为弱符号;同时开发者可以通过"attribute((weak))"来声明一个符号为弱符号;
gcc 在编译过程中,对于强弱符号遵循一定规则进行取舍:

  • 当有多个为强符号时,报"redefinition of 'xxx'"错误

  • 当仅有一个为强符号时,选取强符号的值

  • 当都为弱符号时,选择其中暂用空间较大的符号。(防止溢出越界等问题)-- 这个应该和编译器有关,我在本地环境中,是不允许多个类型不同的弱符号存在的。编译会出错。

很明显,例1 则是出现多个强符号,导致的redefinition 错误。例如下面code:

main.cint strong;int strong=2;int main(){        printf("strong = %d\n",strong);        return 0;}

编译并不会出错,并且输出为2;

强引用与弱引用

我们知道在编译成可执行文件时,若源文件引用了外部目标文件的符号,在链接过程中,需要找到对应的符号定义,若未找到对应符号(未定义),链接器会报符号位未定义错误,导致编译出错。这种被称为强引用。与相对应的时弱引用(开发者可通过attribute((weakref))声明),链接器在链接符号过程中,若发现符号为弱引用,即使没有找到符号定义,链接时也不会报错,但是会将该引用默认为0
书中的代码如下:

main.cint strong;int strong=2;int main(){        printf("strong = %d\n",strong);        return 0;}

虽然没有定义foo(),但是我们可以将它编译成可执行文件,并且GCC 编译不会报链接错误,但是当我们运行时,会发生运行错误。实际上新版本的编译器上诉的代码会在链接时报错的,新版本的示例代码应该如下:(新版本的weakref 需要函数别名,且必须是static 修饰)

main.cstatic __attribute__((weakref("foo"))) void myfoo(void);void main(void){        if(myfoo)        {                myfoo();        }}

新版的弱符号引用如上所示。即表示若没有找到foo函数,编译不报错,但是会默认myfoo为NULL。若在其他库中定义了foo函数,对myfoo的引用就相当于对foo的引用。这种弱引用在库的使用上十分有用的。

小节

经过上面的描述,我们了解到了强符号,弱符号,强引用,弱引用的概念。我认为起码有两点特性可以在我们工作中使用:

  • 强符号可以替换弱符号。

  • 弱引用可以避免函数未定义的错误。

强符号替换弱符号

一些库中对外接口可以声明为弱符号。比如:
在math库中,我们发现add(int num1, int num2)这个接口存在问题,那我们解决方式一般有以下几种:
1. 实现一个myadd(int num1,int num2)接口,之后再将项目中的所有add,替换为myadd。这种方式可行,但是存在缺点:修改量大,并且后续人员不清楚背景,很有可能继续使用熟悉的add接口。
2. 更新math库,从更本解决此问题。这种方式比较推荐。但是也并不是通用的,比如有些库并不是开源的,并且已经过了支持日期,也就不适用了。

此时,我们可以自己在项目中定义一个add(int num1,int num2)接口,用强符号替换库中的弱符号,这样改动是比较小的。(这种情景需要了解接口的实现内容,可给调用者较高的重构权力)

巧用弱引用提高代码的健壮性

应用层的开发,离不开sdk的提供,一般sdk维护了,即使应用没有需求发生,往往也会为了配合sdk,进行简单的修改。以设备升级作为举例,若升级过程中,分为传包(pass),验签(verify),解密(decode),安装(install),上传日志(report)等步骤,并且这些核心接口都是以libsdk.so库的形式提供给应用工程师。那么正常情况下,应用逻辑大致如下:

用户业务流程...pass();...verify();...decode();...install();...report();...

但是这样的业务代码,我觉得是非常差的。比如新的项目中,不需要做解密包操作了,(理论上libsdk.so库中应该不具备decode接口了),这样就会导致应用程序编译失败。undefine 'decode'
因此我建议应用代码可以如下:

static __attribute__((weakref("pass"))) void mypass(void);static __attribute__((weakref("verify"))) void myverify(void);static __attribute__((weakref("decode"))) void mydecode(void);static __attribute__((weakref("install"))) void myinstall(void);static __attribute__((weakref("report"))) void myreport(void);用户业务流程...if(mypass)        mypass();else        printf("don't need pass\n");...if(myverify)        myverify();else        printf("don't need verify\n");...if(mydecode)        mydecode();else        printf("don't need decode\n");...if(myinstall)        myinstall();else        printf("don't need install\n");...if(myreport)        myreport();else        printf("don't need report\n");...

关于"C语言中弱符号与弱引用怎么用"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

符号 编译 作用 变量 错误 代码 接口 文件 链接 应用 函数 编译器 过程 问题 语言 业务 全局 多个 方式 篇文章 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 网络安全公益的心得体会 mc的服务器是谁家的 数据库文件和脚本文件是 安卓手机数据库制作 阿里云服务器关联用户 账套在数据库用户表列 网络安全法针对国外吗 大数据下的网络安全论文摘要 江苏科研oa管控软件开发平台 免流服务器哪里有 浪潮服务器不能引导u盘启动 地下城首页卡在正在连接服务器 南网数研院网络安全事业部经理 达梦数据库查找存储过程 尚德网络技术有限公司标语 网络技术人员都做什么 vc给数据库表添加字段 华为软件开发入职 移动软件开发工程师是学什么的 本地数据库被占用 湖南郴州计算机软件开发工资 找不到服务器文件和应用程序 数据库中索引的工作原理 豫教思语网络安全题库 华为企业级服务器总代理 邵阳串口服务器报价 北邮网络安全专业女孩好学吗 闵行区网络软件开发是什么 上海中友通信网络技术 软件开发应用的合作模式
0