一、强符号和弱符号

在C语言中,如果多个模块定义同名全局符号时,链接器认为函数和已初始化的全局变量(包括显示初始化为0)是强符号,未初始化的全局变量是弱符号。

根据这个定义,Linux链接器使用下面的规则来处理多重定义的符号名:

1.不允许有多个同名的强符号

2.如果有一个强符号和多个弱符号同名,那么选择强符号

3.如果有多个弱符号同名,有些编译器从这些弱符号中任意选择一个,有些编译器选择占用内存最大的那个符号

符号链接原理:链接器发现同时存在弱符号和强符号,优先选择强符号,如果发现不存在强符号,只存在弱符号,则选择弱符号

二、weak的使用

对于初始化的各种函数,我们不确定其他地方是否有这个函数,但是我们不得不用这个函数,即在初始化过程中必须得有这个函数。在这种情况下,可以使用__attribute__关键字的weak属性来声明一个弱符号。

//weak.c
#include <stdio.h>
// int fun1()
// {// printf("new %s\n",__FUNCTION__);// return 0;
// }
int main()
{fun1();return 0;
}
//test.c
#include <stdio.h>
int fun1() __attribute__((weak));int fun1()
{printf("%s\n",__FUNCTION__);return 0;
}

在注释掉weak.c中的fun1时,编译运行

gcc -o weak weak.c teat.c
./weak

输出结果为:

fun1

接下来,我们把对fun1的注释去掉,同样编译运行,运行结果为:

new fun1

三、alias的使用

在使用weak声明弱符号之后,我们需要将每个弱符号函数都定义为一个空函数,如果每个函数都分开写的话,重复量很大,也比较浪费时间。所以可以用alias属性来给每个函数起别名。

#include <stdio.h>int fun1()
{printf("%s\n",__FUNCTION__);return 0;
}int fun() __attribute__((alias("fun1")));int main()
{fun();return 0;
}

代码中fun的别名是fun1,所以运行结果为:

fun1

四、weak和alias结合使用

//test_attribute.c
#include <stdio.h>int fun1()
{printf("%s\n",__FUNCTION__);return 0;
}int fun2() __attribute__((weak, alias("fun1")));
int fun3() __attribute__((weak, alias("fun1")));
//attribute.c
#include <stdio.h>int fun2()
{printf("%s\n",__FUNCTION__);return 0;
}int main()
{fun2();fun3();return 0;
}

fun2是强符号,fun3没有初始化,而fun2和fun3的别名均为fun1,运行结果为:

fun2
fun1

五、使用weak和alias对可执行文件的影响

先看使用weak和alias时的代码

//test_attribute.c
#include <stdio.h>int fun1()
{printf("%s\n",__FUNCTION__);return 0;
}int fun2() __attribute__((weak, alias("fun1")));
int fun3() __attribute__((weak, alias("fun1")));
int fun4() __attribute__((weak, alias("fun1")));
int fun5() __attribute__((weak, alias("fun1")));
int fun6() __attribute__((weak, alias("fun1")));
int fun7() __attribute__((weak, alias("fun1")));
int fun8() __attribute__((weak, alias("fun1")));
int fun9() __attribute__((weak, alias("fun1")));
int fun10() __attribute__((weak, alias("fun1")));
int fun11() __attribute__((weak, alias("fun1")));
int fun12() __attribute__((weak, alias("fun1")));
int fun13() __attribute__((weak, alias("fun1")));
//attribute.c
#include <stdio.h>
int main()
{fun2();fun3();fun4();fun5();fun6();fun7();fun8();fun9();fun10();fun11();fun12();fun13();return 0;
}

链接之后生成的文件大小为:8987。那么如果将weak和alias去掉,同时将这么多fun全部重新定义,

//test_attribute.c
#include <stdio.h>int fun1()
{printf("%s\n",__FUNCTION__);return 0;
}// int fun2() __attribute__((weak, alias("fun1")));
// int fun3() __attribute__((weak, alias("fun1")));
// int fun4() __attribute__((weak, alias("fun1")));
// int fun5() __attribute__((weak, alias("fun1")));
// int fun6() __attribute__((weak, alias("fun1")));
// int fun7() __attribute__((weak, alias("fun1")));
// int fun8() __attribute__((weak, alias("fun1")));
// int fun9() __attribute__((weak, alias("fun1")));
// int fun10() __attribute__((weak, alias("fun1")));
// int fun11() __attribute__((weak, alias("fun1")));
// int fun12() __attribute__((weak, alias("fun1")));
// int fun13() __attribute__((weak, alias("fun1")));
//attribute.c
#include <stdio.h>int fun2()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun3()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun4()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun5()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun6()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun7()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun8()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun9()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun10()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun11()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun12()
{printf("%s\n",__FUNCTION__);return 0;
}
int fun13()
{printf("%s\n",__FUNCTION__);return 0;
}int main()
{fun2();fun3();fun4();fun5();fun6();fun7();fun8();fun9();fun10();fun11();fun12();fun13();return 0;
}

在这种情况下,生成的可执行文件的大小为:9473。可见利用weak和alias可以节省可执行文件的占用空间。

六、函数有形参的情况

如果函数有形参,具体情况是什么呢?看下面代码,如果别名函数有形参,

//test_attribute.c
#include <stdio.h>int fun1(int a, int b)
{a = 3;printf("%s, %d\n", __FUNCTION__, a);return 0;
}int fun2() __attribute__((weak, alias("fun1")));
//attribute.c
#include <stdio.h>
int main()
{fun2();return 0;
}

运行结果为:

fun1, 3

另外,还有一种情况,强符号函数声明有形参

//test_attribute.c
#include <stdio.h>int fun1(int a, int b)
{a = 3;printf("%s, %d\n", __FUNCTION__, a);return 0;
}int fun2() __attribute__((weak, alias("fun1")));
int fun3() __attribute__((weak, alias("fun1")));
int fun4() __attribute__((weak, alias("fun1")));
int fun5() __attribute__((weak, alias("fun1")));
int fun6() __attribute__((weak, alias("fun1")));
int fun7() __attribute__((weak, alias("fun1")));
int fun8() __attribute__((weak, alias("fun1")));
int fun9() __attribute__((weak, alias("fun1")));
int fun10() __attribute__((weak, alias("fun1")));
int fun11() __attribute__((weak, alias("fun1")));
int fun12() __attribute__((weak, alias("fun1")));
int fun13() __attribute__((weak, alias("fun1")));
//attribute.c
#include <stdio.h>int fun2(int a, int b)
{a = 5;printf("%s, %d\n", __FUNCTION__, a);return 0;
}
int main()
{int a;int b;fun2(a, b);return 0;
}

运行结果为:

fun2, 5

个人理解:

在利用weak和alias设置弱符号函数的时候,实际是将fun2指向了fun1,

而如果另外定义了同样的fun2后,它属于强符号,那么test_sttribute.c声明中的fun2指向的是这个新定义的fun2,

这种实现是对函数名地址的改变,而函数内的形参在设置weak和alias可以不用写入

weak和alias相关推荐

  1. __attribute__ 之weak,alias属性

    Weak Alias 跟 Weak Reference 完全没有任何关系,不过是我在看到 Weak Reference 的时候想到的而已. Weak Alias 是 gcc 扩展里的东西,实际上是函数 ...

  2. 关于GCC属性中的弱符号(weak symbol)

    关于弱符号的解释: 若两个或两个以上全局符号(函数或变量名)名字一样,而其中之一声明为weak symbol(弱符号),则这些全局符号不会引发重定义错误.链接器会忽略弱符号,去使用普通的全局符号来解析 ...

  3. __attribute__ 总结

    attribute是GNU C特色之一,在iOS用的比较广泛.系统中有许多地方使用到. attribute可以设置函数属性(Function Attribute ).变量属性(Variable Att ...

  4. gcc: weak_alias如何使用

    本文主要说明weak和alias是什么和如何使用它 __attribute__是用来说明函数的属性,weak和alias分别是两个属性. (一)强符号和弱符号: 强符号:已经初始化的全局变量和未被we ...

  5. GCC中的弱符号与强符号

    转载自 https://www.cnblogs.com/kernel_hcy/archive/2010/01/27/1657411.html 我们经常在编程中碰到一种情况叫符号重复定义.多个目标文件中 ...

  6. S5PV210-uboot解析(三)-start_armboot解析

    start_armboot解析 start_armboot函数在lib_arm/board.c文件里,除了函数本身,还有一些用到了的定义和宏.S5PV210-uboot解析-start.S解析(二)- ...

  7. 弱符号与弱引用 -> 程序员的自我修养 第3,4章笔记

    1. 在程序中声明并使用节名 先看下面一段有意思的程序 #include <stdio.h>__attribute__((section("abcd"))) int s ...

  8. (转)C语言家族扩展

    (转)C语言家族扩展 翻译: 5.1--5.6 林峰 5.7--5.20 董溥 5.21--5.26 王聪 5.27--5.34 刘洋 5.35--5.43 贾孟树 致谢:感谢陈老师指出其中的一些错误 ...

  9. _attribute用法总结

    attribute是GNU C特色之一,在iOS用的比较广泛.系统中有许多地方使用到. attribute可以设置函数属性(Function Attribute ).变量属性(Variable Att ...

  10. __attribute__((weak))是什么意思

    最近在阅读tcmalloc代码时发现使用了很多__attribute__((weak)),上网搜了以下有所了解. 弱符号: 若两个或两个以上全局符号(函数或变量名)名字一样,而其中之一声明为weak ...

最新文章

  1. Nginx学习3:反向代理实例
  2. python自动化办公都能做什么菜-Python 让我再次在女同学面前长脸了!(真实案例)...
  3. This version of the rendering library is more recent than your version of IntelliJ IDEA.
  4. 团队项目第一篇——NABCD
  5. Map对象与实体类Object对象转换
  6. Ubuntu安装minicom串口工具
  7. 【android自定义控件】LinearLayout定义ActionBar样式
  8. Python OpenCV 美女换装,图像处理取经之旅第 19 天
  9. php input type='button' 颜色,HTML5 input新增type属性color颜色拾取器的实例代码
  10. 网页连接mysql教程_网页怎么连接到数据库?
  11. 分式求二阶导数_第12讲 典型例题与练习参考解答:导数的基本运算法则与高阶导数...
  12. Ubuntu安装deb包
  13. sql之分组TOPN
  14. 编译原理——自下而上的语法分析方法(LR分析法)
  15. 电商平台数据仓库搭建02-Hadoop集群搭建
  16. 2019面试/笔试题(算法题)总结
  17. Latex 绘制函数图像
  18. 《论语》全译——公冶长篇第五
  19. 怎么用显卡计算_显卡性能的软件 3dmark怎么用
  20. nCode:DesignLife案例教程一

热门文章

  1. 《关于雪糕刺客与雪糕护卫激发中国人的创作灵感这件事》
  2. 【python文字游戏】飞花令
  3. 网站地图是什么,怎么制作和查看网站的地图呢?
  4. 在Ubuntu5.1中安装NVIDIA TNT2 M64老式显卡驱动程序..
  5. Nature Reviews Microbiology | 土壤微生物组与同一健康
  6. Array Shrinking(区间DP)
  7. 举个栗子!Tableau 技巧(185):实现多度量嵌套排序
  8. 武汉第一职业教育中心计算机技能高考,武汉市第一职业教育中心
  9. Java8 CompletableFuture(2)回调函数 thenApply thenAccept thenRun
  10. 关于反转的总结(C/C++)