一、强符号和弱符号

在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 ;
}
//test.c
#include <stdio.h>
int fun1() __attribute__((weak)); int fun1()
{
printf("%s\n",__FUNCTION__);
return ;
}

在注释掉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 ;
} int fun() __attribute__((alias("fun1"))); int main()
{
fun();
return ;
}

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

fun1

四、weak和alias结合使用

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

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

fun2
fun1

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

先看使用weak和alias时的代码

//test_attribute.c
#include <stdio.h> int fun1()
{
printf("%s\n",__FUNCTION__);
return ;
} 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 ;
}

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

//test_attribute.c
#include <stdio.h> int fun1()
{
printf("%s\n",__FUNCTION__);
return ;
} // 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 ;
}
int fun3()
{
printf("%s\n",__FUNCTION__);
return ;
}
int fun4()
{
printf("%s\n",__FUNCTION__);
return ;
}
int fun5()
{
printf("%s\n",__FUNCTION__);
return ;
}
int fun6()
{
printf("%s\n",__FUNCTION__);
return ;
}
int fun7()
{
printf("%s\n",__FUNCTION__);
return ;
}
int fun8()
{
printf("%s\n",__FUNCTION__);
return ;
}
int fun9()
{
printf("%s\n",__FUNCTION__);
return ;
}
int fun10()
{
printf("%s\n",__FUNCTION__);
return ;
}
int fun11()
{
printf("%s\n",__FUNCTION__);
return ;
}
int fun12()
{
printf("%s\n",__FUNCTION__);
return ;
}
int fun13()
{
printf("%s\n",__FUNCTION__);
return ;
} int main()
{
fun2();
fun3();
fun4();
fun5();
fun6();
fun7();
fun8();
fun9();
fun10();
fun11();
fun12();
fun13();
return ;
}

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

六、函数有形参的情况

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

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

运行结果为:

fun1, 

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

//test_attribute.c
#include <stdio.h> int fun1(int a, int b)
{
a = ;
printf("%s, %d\n", __FUNCTION__, a);
return ;
} 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 = ;
printf("%s, %d\n", __FUNCTION__, a);
return ;
}
int main()
{
int a;
int b;
fun2(a, b);
return ;
}

运行结果为:

fun2, 

个人理解:

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

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

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

weak和alias的更多相关文章

  1. gcc/g++中weak弱符号及alias别名

    最近查看linux内核代码时,表现了一些编译器选项如__attribute_((weak)).__attribute__( (alias("target"))),一开始不了解,后来 ...

  2. weak alias

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

  3. [development] __attribute__((weak))是干嘛的

    简单的说,就是当发生 “重复定义的时候”.被声明者会被冲突者覆盖掉. 这里还涉及了weak与alias连用的情况. 参见,里边有两个例子,很浅显易懂. https://my.oschina.net/s ...

  4. iOS宏和__attribute__

    本文目录 iOS宏的经典用法 Apple的习惯 __attribute__ iOS宏的经典用法 1.常量宏.表达式宏 #define kTabBarH (49.0f) #define kScreenH ...

  5. 5.24 Declaring Attributes of Functions【转】

    转自:https://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html 5.24 Declaring Attributes o ...

  6. GNU C/C++ __attributes__ GCC中的弱符号与强符号

    最近在看一些源代码,遇到了一些使用__attribute__修饰函数和变量的属性方面的代码,不是太了解,很是汗颜,再此做个总结:   GCC使用__attribute__关键字来描述函数,变量和数据类 ...

  7. 特殊的attribute机制

    __attribute__机制是GNU C的一大特色,可以用来设置函数,变量和数据类型的属性,下面对工作中正好用到的两个属性做下简单介绍. 1. constructor 这个属性指定函数在main函数 ...

  8. linux内核中GNU C __attribute__ 机制的实用

    很多东西,只看看是不行的,要想深入的去了解一个东西,一定要去不断地学习,实践,反思. 说白了就是要去打磨. 在linux中,最近遇到了这样一个定义: int board_usb_init(int in ...

  9. linux kernel笔记

    文章目录 关于linux内核中的__attribute__关键字 Linux kernel启动参数 gdt / ldt PCB 关于linux内核中的__attribute__关键字 part I: ...

随机推荐

  1. 一些AngularJs

    # AngularJs部分 #     详情可参考文档----依赖注入--不是主动地获取而是被动的接收,需要什么就要什么,这样灵活较高,如:$scope ----指令--内部:ng-    如:ng- ...

  2. Python 绘图与可视化 matplotlib(下)

    详细的参考链接:更详细的:https://www.cnblogs.com/zhizhan/p/5615947.html 图像.子图.坐标轴以及记号 Matplotlib中图像的意思是打开的整个画图窗口 ...

  3. C# 上位机的USB设备拔插检测

    我们做USB通信时,通信成功后,往往要检测USB设备的拔插状态,这里就USB拔插进行一下说明. 参考:https://www.imooc.com/article/17438 先说明一下,我这里只是用C ...

  4. web.xml中Filter过滤器标签说明

    原文:http://www.cnblogs.com/edwardlauxh/archive/2010/03/11/1918618.html 在研究liferay框架中看到Web.xml中加入了过滤器的 ...

  5. HDU 3073 Saving Beans

    Saving Beans Time Limit: 3000ms Memory Limit: 32768KB This problem will be judged on HDU. Original I ...

  6. 用​M​y​E​c​l​i​p​s​e​ ​打​包​J​A​R文件

    用​M​y​E​c​l​i​p​s​e​ ​将自己定义标签打​成​J​A​R​包 1.新建一个javaproject 2.将标签有关的java代码拷贝到新建javaproject的一个包中,这时会报错 ...

  7. Android Material Design-Getting Started(入门)-(一)

    转载请注明出处:http://blog.csdn.net/bbld_/article/details/40400343 翻译自:http://developer.android.com/trainin ...

  8. 自己主动化測试程序之中的一个自己定义键盘的模拟測试程序(C语言)

    一.測试程序编写说明 我们做的终端设备上运行的是QT应用程序.使用自己定义的键盘接口.经过測试人员长时间的人机交互測试,来确认系统的功能是否满足需求. 如今须要编写一个自己主动化的測试程序,能够依照预 ...

  9. HDU 5228 ZCC loves straight flush( BestCoder Round #41)

    题目链接:pid=5228">ZCC loves straight flush pid=5228">题面: pid=5228"> ZCC loves s ...

  10. 前端防止button被多次点击

    前端的部分逻辑有时候控制前端的显示.比方记录收藏数目等等.有时候多次反复点击会造成前端显示的bug.所以须要有部分逻辑推断去筛除掉反复多次的点击. 实现部分代码例如以下,主要是通过setTimeout ...