• weak和alias


    一、强符号和弱符号

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

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

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

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

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

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

    二、weak的使用

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

    //weak.c
    #include <stdio.h>
    // int fun1()
    // {
        // printf("new %s
    ",__FUNCTION__);
        // return 0;
    // }
    int main()
    {
      fun1();
      return 0;
    }
    //test.c
    #include <stdio.h>
    int fun1() __attribute__((weak));
    
    int fun1() 
    {
      printf("%s
    ",__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
    ",__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
    ",__FUNCTION__);
      return 0;
    }
     
    int fun2() __attribute__((weak, alias("fun1")));
    int fun3() __attribute__((weak, alias("fun1")));
    //attribute.c
    #include <stdio.h>
    
    int fun2() 
    {
      printf("%s
    ",__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
    ",__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
    ",__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
    ",__FUNCTION__);
        return 0;
    }
    int fun3() 
    {
        printf("%s
    ",__FUNCTION__);
        return 0;
    }
    int fun4() 
    {
        printf("%s
    ",__FUNCTION__);
        return 0;
    }
    int fun5() 
    {
        printf("%s
    ",__FUNCTION__);
        return 0;
    }
    int fun6() 
    {
        printf("%s
    ",__FUNCTION__);
        return 0;
    }
    int fun7() 
    {
        printf("%s
    ",__FUNCTION__);
        return 0;
    }
    int fun8() 
    {
        printf("%s
    ",__FUNCTION__);
        return 0;
    }
    int fun9() 
    {
        printf("%s
    ",__FUNCTION__);
        return 0;
    }
    int fun10() 
    {
        printf("%s
    ",__FUNCTION__);
        return 0;
    }
    int fun11() 
    {
        printf("%s
    ",__FUNCTION__);
        return 0;
    }
    int fun12() 
    {
        printf("%s
    ",__FUNCTION__);
        return 0;
    }
    int fun13() 
    {
        printf("%s
    ",__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
    ", __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
    ", __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
    ", __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可以不用写入

  • 相关阅读:
    Do you want a timeout?
    [整]常用的几种VS编程插件
    [转]Windows的窗口刷新机制
    [整][转]Invoke和BeginInvoke的使用
    [整]C#获得程序路径
    [转]Visual Studio 2010 单元测试目录
    飞秋的实现原理
    面向对象的七大原则
    [转]玩转Google开源C++单元测试框架Google Test系列
    [转]C#中的Monitor类
  • 原文地址:https://www.cnblogs.com/zzdbullet/p/9883507.html
Copyright © 2020-2023  润新知