浅谈C语言中的强符号、弱符号、强引用和弱引用【转】
转自:http://www.jb51.net/article/56924.htm
首先我表示很悲剧,在看《程序员的自我修养--链接、装载与库》之前我竟不知道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 = 2;
代码b.c:
int i;
int main(int argc, char** argv)
{
printf("i = %d\n", i);
return 0;
}
编译文件a和b并链接,结果输出i为2而不是0。
并且在同一个文件中定义但未初始化两个相同的变量不会报错,只有在使用变量时才会报错。
对于GCC编译器来说,还允许使用__attribute__((weak))来将强符号定义为弱符号,所已有
代码c.c
__attribute__((weak)) int i = 1;
int main(int argc, char** argv)
{
printf("i = %d\n", i);
return 0;
}
结果i的输出仍未2而不是1。
那么对于函数而言是不是也这样呢?先不看函数,而是先看由强弱符号而进一步引入的强弱引用。书中关于强弱引用的概述是对于强引用若未定义则链接时肯定会报错,而对于弱引用则不会报错,链接器默认其为0(这一点对于函数好理解,即函数符号所代表入口地址为0;对于变量就要注意了,既然是引用那自然就是地址了,所以同函数一样变量的地址为0而不是变量的值为0)。此时对于强弱引用是不是还没有什么明确的概念呢?到底什么是引用?引用和符号又是什么关系?这里我说一下我的理解(欢迎指正),在定义和声明处指定的函数名、变量名即为对应的符号,而在代码其他处调用函数或使用变量时,则把函说明和变量名看作引用,这样一来符号和引用在代码层面上其实就是一个东西,只是根据环境而叫法不同而已。那么强符号对应强引用,弱符号对应弱引用。
有上面的强弱引用的特点可看出,当一个函数为弱引用时,不管这个函数有没有定义,链接时都不会报错,而且我们可以根据判断函数名是否为0来决定是否执行这个函数。这样一来,包含这些函数的库就可以以模块、插件的形式和我们的引用组合一起,方便使用和卸载,并且由于强符号可以覆盖弱符号和强弱符号与强弱引用的关系可知,我们自己定义函数可以覆盖库中的函数,多么美妙。
先看根据条件判断是否执行函数:
代码d.c
void func()
{
printf("func()#1\n");
}
代码e.c
__attribute__((weak)) void func();
int main(int argc, char** argv)
{
if (func)
func();
return 0;
}
编译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
__attribute__((weak)) void func()
{
printf("func()#1\n");
}
代码g.c
void func()
{
printf("func()#2\n");
}
int main(int argc, char** argv)
{
func();
return 0;
}
~
编译链接,结构输出"func()#2"。
以上可以说明函数和变量是保持一致的,其实对应变量也可以像使用函数那样先判断再使用,只不过不是判断变量的值而是变量的地址,如
代码v1.c
代码v2.c
__attribute__((weak)) extern int i;
int main(int argc, char** argv)
{
if (&i)
printf("i = %d\n", i);
return 0;
}
~
编译并链接v1时,输出2;编译但不链接v1时无输出。这样做时要分清定义和声明的区别,__attribute__((weak)) int
i 是定义变量并转换为弱符号,这样i是分配了空间的,而__attribute__((weak)) extern int i
则将原来定义的变量i由强符号转换为弱符号,导致使用i时不是强引用而是弱引用。不过虽然变量可以这么做但没有函数那样有意义。
上面关于强弱引用仍旧使用的是GCC提供的__attribute__((weak)),而书中还提到了__attribute__((weakref)),后者貌似更能体现“引用”这一关键词。而我之所以使用前者来介绍强弱引用,是因为我对关于强弱符号与强弱引用对应关系的理解。关于__attribute__((weakref))的使用方法,这里介绍一种(两者都有不同的使用方法)。
代码a.c
void bar()
{
printf("foo()\n");
}
代码b.c
static void foo() __attribute__((weakref("bar")));
int main(int argc, char** argv)
{
if (foo)
foo();
return 0;
}
注意函数foo的static修饰符,没有的话会报错,这样将函数foo限制在只有本文件内可使用。
浅谈C语言中的强符号、弱符号、强引用和弱引用【转】的更多相关文章
- 浅谈C语言中的强符号、弱符号、强引用和弱引用
摘自http://www.jb51.net/article/56924.htm 浅谈C语言中的强符号.弱符号.强引用和弱引用 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2014- ...
- 浅谈 C 语言中模块化设计的范式
今天继续谈模块化的问题.这个想慢慢写成个系列,但是不一定连续写.基本是想起来了,就整理点思路出来.主要还是为以后集中整理做点铺垫. 我们都知道,层次分明的代码最容易维护.你可以轻易的换掉某个层次上的某 ...
- 浅谈C语言中的联合体
联合体union 当多个数据须要共享内存或者多个数据每次仅仅取其一时.能够利用联合体(union).在C Programming Language 一书中对于联合体是这么描写叙述的: 1)联合体是一个 ...
- 浅谈c语言中的堆
操作系统堆管理器管理: 堆管理器是操作系统的一个模块,堆管理内存分配灵活,按需分配. 大块内存: 堆内存管理者总量很大的操作系统内存块,各进程可以按需申请使用,使用完释放. 程序手动申请&释放 ...
- 浅谈C#语言中的各种数据类型,与数据类型之间的转换
什么是数据类型? 数据类型,百度百科是这样解释的:数据类型在数据结构中的定义是一个值的集合以及定义在这个值集上的一组操作.这样的解释对于一个初学者来说未必太过于深奥. 简单点说,数据类型就是不同长度的 ...
- 浅谈C语言中结构体的初始化
转自:http://www.jb51.net/article/37246.htm <代码大全>建议在变量定义的时候进行初始化,但是很多人,特别是新人对结构体或者结构体数组定义是一般不会初始 ...
- 转: 浅谈C/C++中的指针和数组(二)
转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242419.html 浅谈C/C++中的指针和数组(二) 前面已经讨论了指针和数组 ...
- 转:浅谈C/C++中的指针和数组(一)
再次读的时候实践了一下代码,结果和原文不一致 error C2372: 'p' : redefinition; different types of indirection 不同类型的间接寻址 /// ...
- 浅谈关于QT中Webkit内核浏览器
关于QT中Webkit内核浏览器是本文要介绍的内容,主要是来学习QT中webkit中浏览器的使用.提起WebKit,大家自然而然地想到浏览器.作为浏览器内部的主要构件,WebKit的主要工作是渲染.给 ...
随机推荐
- MVC绕过登陆界面验证时HttpContext.Current.User.Identity.Name取值为空问题解决方法
Global.asax界面添加如下方法: void FormsAuthentication_Authenticate(object sender, FormsAuthenticationEventAr ...
- RT-thread内核之消息队列
一.消息队列控制块:在include/rtdef.h中 #ifdef RT_USING_MESSAGEQUEUE /** * message queue structure */ struct rt_ ...
- poj1065-Wooden Sticks
题目 有很多小木棍需要机器处理.每个小木棍有重量和长度两个属性.不断把小木棍放入机器中,如果小木棍\(a\)放完后放入小木棍\(b\),那么如果\(a.weight<=b.weight\ and ...
- 【bzoj1441】Min 扩展裴蜀定理
题目描述 给出n个数(A1...An)现求一组整数序列(X1...Xn)使得S=A1*X1+...An*Xn>0,且S的值最小 输入 第一行给出数字N,代表有N个数 下面一行给出N个数 输出 S ...
- csrf漏洞攻击手段和影响详解
针对web应用安全中csrf漏洞两种典型的攻击方式:即输入和执行,这种简单模式下的攻击手段以及中途包含确认页面的攻击方法. 图解什么是csrf漏洞 我们先进行约束,比如存在csrf漏洞的网站叫webA ...
- html的body内标签之多行文本及下拉框
一,<textarea>默认值<textarea> -name属性,textarea的默认值放到中间 <select> name,内部option value,提 ...
- CentOS 文本搜索grep
grep 用于在文本中执行关键词搜索, 用法: grep [选项]... PATTERN [FILE]... [root@bigdata-senior01 ~]# grep "ftp&quo ...
- 【POJ2976】Dropping Tests(分数规划)
[POJ2976]Dropping Tests(分数规划) 题面 Vjudge 翻译在\(Vjudge\)上有(而且很皮) 题解 简单的\(01\)分数规划 需要我们做的是最大化\(\frac{\su ...
- 洛谷 P3620 [APIO/CTSC 2007]数据备份 解题报告
P3620 [APIO/CTSC 2007]数据备份 题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同 ...
- 【计数】【UVA11401】 Triangle Counting
传送门 Description 把1……n这n个数中任取3个数,求能组成一个三角形的方案个数 Input 多组数据,对于每组数据,包括: 一行一个数i,代表前i个数. 输入结束标识为i<3. O ...