C语言中的__attribute__((weak)) 与 attribute ((weakref())

引言:最近在看 linux 中一些驱动代码。驱动代码中为了实现程序的扩展性和兼容性用了很多 C 语言中的高级特性。本节就来谈一谈 C 语言中的弱符号和弱引用的用法。

弱符号

弱符号是指在定义或者声明一个对象(变量、结构体成员、函数)时,在对象的前面添加 __attribute__((weak)) 标志所得到的对象符号。如下所示函数即为一个弱对象符号 void test_weak_attr(void),或者称该函数是弱函数属性的、虚函数。

__attribute__((weak)) void test_weak_attr(void)
// 或者使用如下样式的定义,两者等效
void __attribute__((weak)) test_weak_attr(void)
{printf("Weak Func!\r\n");
}

弱符号的作用与示例

弱符号是相对于强符号而言的,在定义或者声明变量、函数时,未添加 __attribute__((weak)) 标识的就默认为强符号。如下,最普通的函数定义,就是定义了一个强符号 void test_strong_ref(void):

void test_weak_attr(void)
{printf("this is a strong func\r\n");
}

驱动程序往往需要考虑兼容性,因为要兼任很多厂商的不同型号的设备。若驱动程序中使用强符号定义一些与适配的设备的特性相关的功能,则下次适配其他设备时,该强符号函数可能需要被修改,以兼容新的设备。当适配的设备很多时,频繁地更改驱动代码将破坏驱动的可维护性。
弱符号的出现可以很好地解决该问题。弱符号的对象具有可以被重定义的功能(即可以被重载)。下面通过测试说明弱符号这种可被重载的特性。
在 test_weak_attr.c 程序中定义如下弱函数:

// test_weak_attr.c
#include <stdio.h>__attribute__((weak)) void test_weak_attr(void)
{printf("this is a weak func\r\n");
}

在 main.c 中定义如下程序:

// main.c
void test_weak_attr(void)
{printf("this is a strong func\r\n");
}void app_main(void)
{printf("init done\r\n");test_weak_attr();
}

编译运行该 main.c 程序,得到的结果是什么样子的呢?

this is a strong func

将 main.c 中的 void test_weak_attr(void) 函数注释掉,再重新编译运行程序得到的结果是:

this is a weak func

小结:在使用弱符号函数时,我们可以重新定义一个同名的强符号函数来替代它;若没有重新定义一个强函数来替换它,就使用弱函数的实现。弱函数就好像是一个可以被替换的“默认函数”。

值得一提的是,旧版本的编译器还可以使用如下方式的定义(仅声明无效)将一个对象定义为一个弱对象:

__weak void f(void)
{//code
}

在 linux 的一些代码中,__weak 其实就是通过 __attribute__((weak))的重命名,两者等效。

弱引用

弱引用是在声明一个对象时,通过__attribute__ ((weakref()) 定义一个符号的引用关系。如下所示即定义 test_weakref() 函数弱引用 test_weak_ref() 函数。

static void test_weakref(void) __attribute__ ((weakref("test_weak_ref")));

弱引用是相对于强引用而言的。未通过 __attribute__ ((weakref()) 的符号和实现代码之间的关系是强引用。如下即为一个强引用函数。它直接给出了 函数 test_strong_ref(void) 的实现。

static void test_strong_ref(void)
{printf("this is a strong ref\r\n");
}

在编译程序的时候,我们可以直接使用 test_strong_ref(void) 而不必担心编译不通过。如果,我没有时间去实现 test_strong_ref(void) ,还想在程序里先使用该函数那该如何呢?(是的,就是想白嫖,不想实现,还想先在程序里使用这个函数)。

这个时候弱引用就派上用场了。可以先将该函数定义为弱引用插入到代码中,待后期有时间再慢慢优化代码实现这个函数完整的功能。下面结合测试进行说明。

测试代码1:

static void test_weakref(void) __attribute__ ((weakref("test_weak_ref")));
void app_main(void)
{printf("init done\r\n");if (test_weakref) {test_weakref();} else {printf("There is no weakref\r\n");}
}

测试结果:

There is no weakref

测试代码2:

void test_weak_ref(void)
{ printf("this is a weak ref\n");
}
static void test_weakref(void) __attribute__ ((weakref("test_weak_ref")));
void app_main(void)
{printf("init done\r\n");if (test_weakref) {test_weakref();} else {printf("There is no weakref\r\n");}
}

测试结果:

this is a weak ref

小结: 强引用,在未定义该强引用的实现时,编译会报错误:未定义的引用。弱引用允许定义一个未实现(未实例化)的对象,这在编译的时候会将该对象处理成 NULL,编译器并不会报错。通过使用弱引用可以实现后期优化代码的功能。而避免改动使用该函数的地方。使用弱函数可以实现类似“钩子(hook)"函数的功能。
实际上,包括C、python、go 编程语言在内的很多语言 都有类似用法,本篇文章叙述的方法同样适用于这些语言的相关开发。
注意:弱引用仅在静态编译中有效,动态链接中可能无效。

总结

弱符号、弱引用都是增强程序的可维护性的方法。弱符号通过可以被重定义的特性,实现可以被替换实现。弱引用通过可以暂时使用一个未定义的函数的功能,实现允许后期再实现该函数具体功能,而不必担心编译不通过。

今天又学会了新知识呢。
(码字不易,谢谢点赞或收藏,我是老王,热爱分享的技术爱好者)

详解 C 语言中的弱符号与弱引用相关推荐

  1. c语言 字符串 strncpy,详解c语言中的 strcpy和strncpy字符串函数使用

    详解c语言中的 strcpy和strncpy字符串函数使用 strcpy 和strcnpy函数--字符串复制函数. 1.strcpy函数 函数原型:char *strcpy(char *dst,cha ...

  2. 武林c语言,详解C语言中条件编译

    预处理器提供条件编译,程序的不同部分可以在不同的条件下编译,从而产生不同的目标代码文件,这对于程序移植和调试非常有用,本文是武林技术频道小编给为大家带来的详解中条件编译,一起来了解一下吧! 通常情况, ...

  3. c语言弱符号与函数指针,浅谈C语言中的强符号、弱符号、强引用和弱引用【转】...

    首先我表示很悲剧,在看<程序员的自我修养--链接.装载与库>之前我竟不知道C有强符号.弱符号.强引用和弱引用.在看到3.5.5节弱符号和强符号时,我感觉有些困惑,所以写下此篇,希望能和同样 ...

  4. 详解C语言中头文件的作用

    大家好,先做个自我介绍,我是天蓬,欢迎阅读本篇博文. 由于本人理解能力不是很好,阅读他人文章时,常常看得晕头晕脑,这让我很是头疼,我想,世界上一定还有和我一样的人(哈哈,不是说你么笨哦).所以,我将会 ...

  5. C语言中的强符号与弱符号

    注意,强符号和弱符号都是针对定义来说的,不是针对符号的引用. 一.概述 在C语言中,函数和初始化的全局变量(包括显示初始化为0)是强符号,未初始化的全局变量是弱符号. 对于它们,下列三条规则使用: ① ...

  6. C语言中的强符号与弱符号(关于变量声明与定义的深入讨论)

    看到一篇介绍C语言强符号与弱符号的文章非常好,转载过来加深印象. 原文地址:http://blog.csdn.net/astrotycoon/article/details/8008629 ===== ...

  7. (计算机组成原理)第二章数据的表示和运算-第二节7:详解C语言中的强制类型转换

    文章目录 (1)无符号数和有符号数 (2)长整数变为短整数 (3)短整数变为长整数 在学习完前面几节的内容后,相信大家对数据是如何在计算机中存储.运算的有了更加深入的认识,那么接下来我们就以更深层次的 ...

  8. C语言中的强符号和弱符号

    一.强弱符号 强弱符号针对的是处于同一工程下在不同源文件下定义的全局变量符号,链接器只处理global的符号而不处理local的符号.链接的核心是符号的重定位,在符号引用的地方找到符号定义的地方,包括 ...

  9. 详解C语言中的位操作运算符可以怎么用?

    目录 前言 位运算符介绍 位运算符的应用 一般案例 特殊用法 前言 最近在工作中碰到C语言中的位操作运算符,然后发现自己对这一块的内容比较模糊,所以打算写一篇博文记录这个知识点,今天是3月份的最后一天 ...

最新文章

  1. 澎思科技马原:AI为基,IoT为翼,加速人工智能普惠丨MEET2021
  2. C语言atoi()函数用法
  3. mailmessage html编码,C#MailMessage顯示HTML標記的AlternateViews
  4. 日常shell使用小结
  5. 成功解决TypeError: take() got an unexpected keyword argument ‘fill_value‘
  6. [算法系列之二十六]字符串匹配之KMP算法
  7. 体验 vue cli 3.0
  8. frontcon函数用不了_真香警告!用了XLOOKUP再也回不去VLOOKUP了
  9. JS组件系列——Bootstrap Table 表格行拖拽
  10. SSM简单参数传递与获取方法
  11. Windows Azure Storage (3) Windows Azure Storage Service存储服务之Blob详解(中)
  12. 删除双系统linux分区,双系统时如何正确删除Linux系统
  13. ASP.NET或者 js方式实现文件夹多图片浏览的方式
  14. 关于Redis的常见面试题解析
  15. SpringMVC之分析HandlerMethodArgumentResolver请求对应处理器方法参数的解析过程(一)
  16. access 数据库入门
  17. python做鼠标自动移动_Python实现鼠标自动在屏幕上随机移动功能
  18. 纯css改变checkbook样式
  19. 中职计算机平面设计主要学什么,四川省计算机平面设计专业学什么
  20. 字节跳动 Java 岗一二三面全经过分享

热门文章

  1. 白岩松谈孩子刷手机上瘾
  2. Java CAS详解
  3. int *和int[]共同点和区别
  4. Chrome商店镜像,支持各种插件下载
  5. linux运行roon,Roon的入门方案
  6. 电脑删除文件遇到“操作无法完成,因为其中的文件夹或文件已在另一应用程序中打开”怎么办
  7. cf-366C-Dima and Salad
  8. 代码随想录算法训练营day42 | 01背包问题,你该了解这些!,01背包问题,你该了解这些! 滚动数组 , 416. 分割等和子集
  9. Deformable CNN 和 Deformable Attention
  10. 视频教程-C语言及程序设计初步-C/C++