一、强符号和弱符号

在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. HDU 2079 选课时间(母函数模板题)

    链接:传送门 思路:母函数模板题 /************************************************************************* > Fil ...

  2. BZOJ 1878 HH的项链 (树状数组+离线)

    题目大意:给你一个序列,求某区间出现不同的数的个数. 貌似离线树状数组是最好的解法 先把所有询问挂在它们询问的右端点上 然后从头到尾遍历这个序列,记录这个位置的值上一次出现的位置 那么,当遍历到第i位 ...

  3. 转载:CentOS查看本机公网IP命令

    icanhazip.com 使你在任何地方知道你的公网IP地址 icanhazip.com是一个网址,你在浏览器中输入这个网址,你就能得到你的公网IP地址了. 我在Linux下一般使用curl ica ...

  4. Could not find result map java.util.HashMap

    Could not find result map java.util.HashMap 找不到结果图java.util.HashMap MyBatis 找不到返回的 'resultMap'!把resu ...

  5. django-9-请求与响应

    写在表单下面{% csrf_token %} <<<文件上传>>>settings.py UPLOAD_ROOT = os.paht.join(BASE_DIR, ...

  6. Golang-and-package-version-managment

    参考文章 学习Golang之后对golang中的版本管理,包管理等机制一直没有很好的琢磨,偶然想起还是觉得很有必要进行归纳,包管理使用起来简单,无非就是install,uninstall,list等, ...

  7. CSS3弹性布局内容对齐(justify-content)属性使用具体解释

    内容对齐(justify-content)属性应用在弹性容器上.把弹性项沿着弹性容器的主轴线(main axis)对齐. 该操作发生在弹性长度以及自己主动边距被确定后. 它用来在存在剩余空间时怎样加以 ...

  8. nyoj--1058--部分和问题(dfs)

    部分和问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 给定整数a1.a2........an,判断是否可以从中选出若干数,使它们的和恰好为K. 输入 首先,n和k, ...

  9. hbase的命令

    1.1. 命令 名称 命令表达式 创建表 create '表名', '列族名1','列族名2','列族名N' 查看所有表 list 描述表 describe  ‘表名’ 判断表存在 exists  ' ...

  10. asp.net mvc5 文件下载上传

    下载:是通过点击a标签直接下载的方式,没有其他任何要求,在服务器上存在实体文件,不需要请求后台控制层 前段js: <a id="NF-DownLoad" authorize= ...