首先我表示很悲剧,在看《程序员的自我修养--链接、装载与库》之前我竟不知道C有强符号、弱符号、强引用和弱引用。在看到3.5.5节弱符号和强符号时,我感觉有些困惑,所以写下此篇,希望能和同样感觉的朋友交流也希望高人指点。

  首先我们看一下书中关于它们的定义。

  引入场景:(1)文件A中定义并初始化变量i(int i = 1), 文件B中定义并初始化变量i(int i = 2)。编译链接A、B时会报错b.o:(.data+0x0): multiple definition of `i';a.o:(.data+0x0): multiple definition of `i'。(2)在文件C中定义并初始化两个变量i(int i = 1; int i = 2), 编译链接时会报错c.c:2:5: error: redefinition of ‘i’; c.c:1:5: note: previous definition of ‘i’ was here。

  强符号:像场景中这样的符号定义被称为强符号,对于C/C++来说,编译器默认函数和初始化的全局变量为强符号。
  弱符号:接上文,为初始化的全局变量为弱符号。
  编译器关于强弱符号的规则有:(1)强符号不允许多次定义,但强弱可以共存;(2)强弱共存时,强覆盖弱;(3)都是弱符号时,选择占用空间最大的,如选择  double类型的而不选择int类型的。

  由以上定义所以有我之前没有想到的场景:
  代码a.c:

  1. int i = ;

  代码b.c:

  1. #include<stdio.h>
  2.  
  3. int i;
  4. int main(int argc, char** argv)
  5. {
  6. printf("i = %d\n", i);
  7. return ;
  8. }

  编译文件a和b并链接,结果输出i为2而不是0。
  并且在同一个文件中定义但未初始化两个相同的变量不会报错,只有在使用变量时才会报错。
  对于GCC编译器来说,还允许使用__attribute__((weak))来将强符号定义为弱符号,所已有
  代码c.c

  1. #include<stdio.h>
  2.  
  3. __attribute__((weak)) int i = ;
  4.  
  5. int main(int argc, char** argv)
  6. {
  7. printf("i = %d\n", i);
  8. return ;
  9. }

  结果i的输出仍未2而不是1。

  那么对于函数而言是不是也这样呢?先不看函数,而是先看由强弱符号而进一步引入的强弱引用。书中关于强弱引用的概述是对于强引用若未定义则链接时肯定会报错,而对于弱引用则不会报错,链接器默认其为0(这一点对于函数好理解,即函数符号所代表入口地址为0;对于变量就要注意了,既然是引用那自然就是地址了,所以同函数一样变量的地址为0而不是变量的值为0)。此时对于强弱引用是不是还没有什么明确的概念呢?到底什么是引用?引用和符号又是什么关系?这里我说一下我的理解(欢迎指正),在定义和声明处指定的函数名、变量名即为对应的符号,而在代码其他处调用函数或使用变量时,则把函说明和变量名看作引用,这样一来符号和引用在代码层面上其实就是一个东西,只是根据环境而叫法不同而已。那么强符号对应强引用,弱符号对应弱引用。

  有上面的强弱引用的特点可看出,当一个函数为弱引用时,不管这个函数有没有定义,链接时都不会报错,而且我们可以根据判断函数名是否为0来决定是否执行这个函数。这样一来,包含这些函数的库就可以以模块、插件的形式和我们的引用组合一起,方便使用和卸载,并且由于强符号可以覆盖弱符号和强弱符号与强弱引用的关系可知,我们自己定义函数可以覆盖库中的函数,多么美妙。

  先看根据条件判断是否执行函数:
  代码d.c

  1. #include<stdio.h>
  2.  
  3. void func()
  4. {
  5. printf("func()#1\n");
  6. }

  代码e.c

  1. #include<stdio.h>
  2.  
  3. __attribute__((weak)) void func();
  4.  
  5. int main(int argc, char** argv)
  6. {
  7. if (func)
  8. func();
  9. return ;
  10. }

  编译d.c,cc -c d.c 输出d.o;编译e.c并链接d.o,cc d.o e.c -o e输出可执行文件e,运行e正常执行函数func。编译e.c但不链接d.o,此时并不会报错,只不过func不会执行,因为没有它的定义所以if(func)为假。
  再看函数覆盖:
  代码f.c

  1. #include<stdio.h>
  2.  
  3. __attribute__((weak)) void func()
  4. {
  5. printf("func()#1\n");
  6. }

  代码g.c

  1. #include<stdio.h>
  2.  
  3. void func()
  4. {
  5. printf("func()#2\n");
  6. }
  7.  
  8. int main(int argc, char** argv)
  9. {
  10. func();
  11. return ;
  12. }
  13. ~

  编译链接,结构输出"func()#2"。

  以上可以说明函数和变量是保持一致的,其实对应变量也可以像使用函数那样先判断再使用,只不过不是判断变量的值而是变量的地址,如
  代码v1.c

  1. int i = ;

  代码v2.c

  1. #include<stdio.h>
  2.  
  3. __attribute__((weak)) extern int i;
  4.  
  5. int main(int argc, char** argv)
  6. {
  7. if (&i)
  8. printf("i = %d\n", i);
  9. return ;
  10. }
  11. ~

  编译并链接v1时,输出2;编译但不链接v1时无输出。这样做时要分清定义和声明的区别,__attribute__((weak)) int i 是定义变量并转换为弱符号,这样i是分配了空间的,而__attribute__((weak)) extern int i 则将原来定义的变量i由强符号转换为弱符号,导致使用i时不是强引用而是弱引用。不过虽然变量可以这么做但没有函数那样有意义。

  上面关于强弱引用仍旧使用的是GCC提供的__attribute__((weak)),而书中还提到了__attribute__((weakref)),后者貌似更能体现“引用”这一关键词。而我之所以使用前者来介绍强弱引用,是因为我对关于强弱符号与强弱引用对应关系的理解。关于__attribute__((weakref))的使用方法,这里介绍一种(两者都有不同的使用方法)。
  代码a.c

  1. #include<stdio.h>
  2.  
  3. void bar()
  4. {
  5. printf("foo()\n");
  6. }

  代码b.c

  1. #include<stdio.h>
  2.  
  3. static void foo() __attribute__((weakref("bar")));
  4.  
  5. int main(int argc, char** argv)
  6. {
  7. if (foo)
  8. foo();
  9.  
  10. return ;
  11. }

  注意函数foo的static修饰符,没有的话会报错,这样将函数foo限制在只有本文件内可使用。

  好了,夜已深,写的有点凌乱,我也凌乱了。

关于C语言中的强符号、弱符号、强引用和弱引用的一些陋见,欢迎指正的更多相关文章

  1. C语言中无符号数和有符号数之间的运算

    C语言中无符号数和有符号数之间的运算 C语言中有符号数和无符号数进行运算(包括逻辑运算和算术运算)默认会将有符号数看成无符号数进行运算,其中算术运算默认返回无符号数,逻辑运算当然是返回0或1了. un ...

  2. c语言中为什么左移不分符号数无符号数,而右移分呢??

    因为在C语言标准中,只规定了无符号数的移位操作是采用逻辑移位(即左移.右移都是使用的逻辑左移和逻辑右移).而对于有符号数,其左移操作还是逻辑左移,但右移操作是采用逻辑右移还是算术右移就取决于机器了!( ...

  3. C语言中的强符号与弱符号

    转自:http://blog.csdn.net/astrotycoon/article/details/8008629 一.概述 在C语言中,函数和初始化的全局变量(包括显示初始化为0)是强符号,未初 ...

  4. 浅谈C语言中的强符号、弱符号、强引用和弱引用

    摘自http://www.jb51.net/article/56924.htm 浅谈C语言中的强符号.弱符号.强引用和弱引用 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2014- ...

  5. 嵌入式C语言自我修养 09:链接过程中的强符号和弱符号

    9.1 属性声明:weak GNU C 通过 __atttribute__ 声明weak属性,可以将一个强符号转换为弱符号. 使用方法如下. void __attribute__((weak)) fu ...

  6. 浅谈C语言中的强符号、弱符号、强引用和弱引用【转】

    转自:http://www.jb51.net/article/56924.htm 首先我表示很悲剧,在看<程序员的自我修养--链接.装载与库>之前我竟不知道C有强符号.弱符号.强引用和弱引 ...

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

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

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

    GCC中的弱符号与强符号 我们经常在编程中碰到一种情况叫符号重复定义.多个目标文件中含有相同名字全局符号的定义,那么这些目标文件链接的时候将会出现符号重复定义的错误.比如我们在目标文件A和目标文件B都 ...

  9. GCC中的强符号和弱符号及强引用和弱引用

    1. 强符号和弱符号 1.1 u-boot和kernel中的__weak指令 u-boot和kernel比较普遍地使用了__weak来定义函数. 在include\linux\compiler-gcc ...

随机推荐

  1. C语言复习--实现栈

    C #include <stdio.h> #include <stdlib.h> #define STACK_SIZE 100 typedef char TYPE; typed ...

  2. ActiveX in QT

    http://doc.qt.io/qt-4.8/activeqt.htmlhttp://doc.qt.io/qt-5/activeqt-index.html

  3. 【转】兼容性测试套件(CTS)框架用户手册

    原文网址:http://blog.sina.com.cn/s/blog_416166e90102v6bi.html 兼容性测试套件(CTS)框架用户手册 1.为什么需要兼容性测试(以下称CTS)? 2 ...

  4. 【转】Gedit中文乱码

    原文网址:http://wiki.ubuntu.org.cn/Gedit%E4%B8%AD%E6%96%87%E4%B9%B1%E7%A0%81#.E5.91.BD.E4.BB.A4.E6.96.B9 ...

  5. SSH方式登录github出现Permission denied (publickey)

    今天在公司上传了代码,回到家pull,结果竟然出现了“Permission denied (publickey)“这种东西.第一反应是key不对,可是上次明明用key登录过,不可能不对啊,难道是文件被 ...

  6. Unity 屏幕适配小脚本

    屏幕适配是可以通过代码实现的,相信给你时间就一定能写出来. 我们公司貌似没有分辨率适配框架通常对应小屏幕的苹果4要额外设置下等等就完了! 屏幕适配框架实现思路:  通过代码获取当前的分辨率 –> ...

  7. pyqt tabWidget例子学习1

    from PyQt4 import QtGui from PyQt4 import QtCore from PyQt4.QtCore import pyqtSlot,SIGNAL,SLOT impor ...

  8. python学习之路-8 面向对象之进阶

    上篇内容回顾和补充 面向对象三大特性 封装 继承 多态 在python中没有多态的概念 变量的类型允许为多种数据类型称之为多态 # c#/java中的多态 # 伪代码 def func(int arg ...

  9. hdu 4427 Math Magic

    一个长了一张数学脸的dp!!dp[ i ][ s ][ t ] 表示第 i 个数,sum为 s ,lcm下标为 t 时的个数.显然,一个数的因子的lcm还是这个数的因子,所以我们的第三维用因子下标代替 ...

  10. [Protractor] Locators and Suites in Protractor

    HTML: <ul class="list"> <li ng-repeat="item in itmes" ng-click="se ...