深析静态链接库和动态链接库相同函数覆盖及库调用顺序问题

注意:编译器为gcc,若使用g++,请在库里面加上extern “C”

    两个静态库
    首先测试静态链接库,大概的代码如下:
    liba.c
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "libA.h"
  4. void libA()
  5. {
  6.         common();
  7. }
  8.   
  9. void common()
  10. {
  11.         printf("libA common!\n");
  12. }
    liba.h
  1. #ifndef __LIBA_H__
  2. #define __LIBA_H__
  3.   
  4. void libA();
  5. void common();
  6.   
  7. #endif
    
    libb.c
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "libB.h"
  4. void libB()
  5. {
  6.         common();
  7. }
  8.   
  9. void common()
  10. {
  11.         printf("libB common!\n");
  12. }
    libb.h
  1. #ifndef __LIBB_H__
  2. #define __LIBB_H__
  3.   
  4. void libB();
  5. void common();
  6.   
  7. #endif
    静态库的生成:
  1. gcc -c liba.c
  2. ar -rs liba.a liba.o

  3. gcc -c libb.c
  4. ar -rs libb.a libb.o
    动态库生成:
  1. gcc -fpic -shared -o liba.so liba.c

  2. gcc -fpic -shared -o libb.so libb.c
    fpic:表示为位置无关,也即在任何内存位置都可以运行。

    可以看到liba和libb都有相同的common函数,但是打印出的内容都是自家的。
    下面我们分别生成静态链接库做测试,生成好后,写个主程序进行测试。
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dlfcn.h>
  5.   
  6. int main()
  7. {
  8.         libA();
  9.         libB();
  10.         return 0;
  11. }
    编译生成结果如下:
    
    可以得出一个结论:都为静态链接库,有同名函数参与的情况下,链接会出现符号多次定义的错误。

    两个动态库
    再来看看动态链接库,同样的liba、libb生成动态链接库
    测试主程序不修改,还是为:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dlfcn.h>
  5.   
  6. int main()
  7. {
  8.     liba();
  9.     libb();
  10.     return 0;
  11. }
    编译结果和顺序,结果如下:
    

     
    这种编译方式叫做动态链接库的隐式调用,如果你删除一个liba.so,运行a.out会出现不能找到动态库的错误。
    这种情况也可以称为 加载时链接!静态库属于编译时链接!
     可以得出第二个结论:若都为动态库,并且进行隐式调用,输出结果和动态库的顺序有关。


    再继续看看动态加载动态库。
    修改测试程序
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dlfcn.h>
  5.   
  6. int main()
  7. {
  8.     void* handle2 = NULL;
  9.     void (*testLibA)();
  10.     handle2 = dlopen("./libA.so", RTLD_LAZY);
  11.     if (handle2 == NULL) {
  12.         perror("error!");
  13.         return ;
  14.     }
  15.     testLibA = dlsym(handle2, "libA");
  16.     if (testLibA == NULL) {
  17.         perror("error!");
  18.         return ;
  19.     }
  20.   
  21.   
  22.     void* handle = NULL;
  23.     void (*testLibB)();
  24.     handle = dlopen("./libB.so", RTLD_LAZY);
  25.     if (handle == NULL) {
  26.         perror("error!");
  27.         return ;
  28.     }
  29.     testLibB = dlsym(handle, "libB");
  30.     if (testLibB == NULL) {
  31.         perror("error!");
  32.         return ;
  33.     }
  34.     testLibA();
  35.     testLibB();
  36.   
  37.     return 0;
  38. }
    编译结果如下所示:
    
    这种情况称为运行时链接。
    如果我们再把动态库的名字加上去呢?
    
     
    

    同样可以得出结论:动态链接库如果不加库选项,函数调用是正确的,加库路径,会以库的路径顺序为主!左边覆盖右边。而且当只链接一个时也生效。如:
    

    一个静态,一个动态
    再来看看一个静态文件和一个动态文件。
    修改测试主程序
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dlfcn.h>
  5.   
  6. int main()
  7. {
  8.     void* handle2 = NULL;
  9.     void (*testLibA)();
  10.     handle2 = dlopen("./libA.so", RTLD_LAZY);
  11.     if (handle2 == NULL) {
  12.         perror("error!");
  13.         return ;
  14.     }
  15.     testLibA = dlsym(handle2, "libA");
  16.     if (testLibA == NULL) {
  17.         perror("error!");
  18.         return ;
  19.     }
  20.     testLibA();
  21.   
  22.     libB();
  23.     return 0;
  24. }
    测试结果如下:
    libb为静态链接!liba为动态加载。
    
    输出正常!
    再看下如果动态库的库名显示的加载如编译选项中:
    
    
    
     结论:在有静态库和动态库时,不把动态库名显示加入编译选项,输出是正常的,如果加进去以静态库为主,和link的顺序无关。

    补充:
    
    另外:
    这种一个共享对象里面的全局符号被另一个共享对象的全局符号覆盖的现象又被称为共享对象的全局符号介入。

    关于全局符号介入这个问题,实际上Linux下的动态链接器是这样处理的:它定义了一个规则,那就是当一个符合需要被加入到全局符号表时,如果相同的符号名已经存在,则后加入的忽略。从动态链接器的角度的装载顺序可以看到,它是按广度优先的顺序进行装载的。


原文地址:http://blog.chinaunix.net/uid-26548237-id-3837099.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Attribute: 'NoneType' object has no attribute 'sum'错误是因为在某个对象上调用了一个不存在的属性或方法。在这种情况下,错误指示对象的类型为NoneType,而NoneType类型没有名为'sum'的属性。 通常情况下,出现这个错误是因为在代码中使用了一个未初始化或者未赋值的变量,导致其值为None。例如,在自定义函数中,如果返回值是None,那么在调用函数并尝试访问返回值的属性或方法时就会出现这个错误。比如在中的示例代码,如果函数fun返回的是None,则在调用函数并尝试访问返回值的'sum'属性时会出现AttributeError。 要解决这个错误,你可以检查代码中可能导致返回None的地方,并确保对象的类型正确以及属性或方法存在。你可以使用if语句或其他逻辑来处理None值,以避免出现AttributeError。在中的示例代码中,可以通过添加条件判断来处理返回值为None的情况,或者在调用函数之前进行判断。 总之,AttributeError: 'NoneType' object has no attribute 'sum'错误通常是由于对象的类型为NoneType并且尝试访问不存在的属性或方法所导致的。解决这个错误的方法是检查代码中可能导致返回None的地方,并确保对象的类型正确以及属性或方法存在。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [[报错]深析AttributeError: ‘NoneType‘ object has no attribute ‘xxx‘(持更)](https://blog.csdn.net/panbaoran913/article/details/124650015)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值