最近查看linux内核代码时,表现了一些编译器选项如__attribute_((weak))、__attribute__( (alias("target"))),一开始不了解,后来自己查看资料及书籍算是对gcc的这个编译属性有了一定的认识。

一、先了解weak属性。
__attribute__((weak))表示为弱符号属性,所谓的弱符号是针对于强符号来说的,我们定义的全局已初始化变量及全局函数等都是属于强符号,在链接时如果有多个强符号就会报错误;而弱符号主要指未初始化的全局变量或通过__attribute__((weak))来显式申明的变量或函数。

以下代码示例:

/* file:weak_test.c */

void weak_func_test(void) __attribute__((weak));  /* 显式申明为weak,属于弱符号(函数) */
int weak_var_test; /* 未初始化的全局变量,属于弱符号 */ #ifdef WEAK_SYM
void weak_func_test(void)
{
printf("%s:%s.c in\n", __FILE__, __func__);
}
#endif int main()
{
printf("weak_var_test:%d\n", weak_var_test);
weak_func_test();
return ;
} /* file:symbol.c */
int weak_var_test = ; /* 已初始化的全局变量,属于强符号 */
/* 全局函数属于强符号 */
void weak_func_test(void)
{
  printf("%s:%s() in\n", __FILE__, __func__);
}

1、使用编译命令gcc weak_test.c  symbol.c DWEAK_SYM -o weak_test,执行./weak_test,打印weak_var_test为6666,函数weak_func_test()打印symblo.c:weak_func_test() in(注意是symbol.c的函数),从执行结果看symbol.c的weak_var_test及weak_func_test覆盖了weak_test.c的符号,说明链接时强弱符号都存在时以强符号为准;

2、再使用编译命令而gcc weak_test.c  -DWEAK_SYM -o weak_test,执行./weak_test,打印weak_var_test为0(未初始化的全局变量编译器默认为0),函数执行打印weak_test.c:weak_func_test() in(这时是weak_test.c的函数),说明连接时如果只有弱符号时以弱符号为准。

3、继续编译gcc weak_test.c  -o
weak_test,这时可能大家会有疑问,weak_func_test函数没有实现,那么链接的时候应该会报错吧;实际上肯定是不会的,就是因为我们
将这个函数显式的申明为weak symbol,申明为weak
symbol的函数在.o目标文件里面是以WEAK及UND形式存在的,符号的地址为0,具体可以用readelf -s 命令查看。
那么这种情况下只有弱符号weak_func_test存在,最终链接时也以弱符号为准,只不过此函数的地址为0,所以这时我们去执行./weak_test的时候必然会有segement fault的错误产生,就是因为去访问了null指针。

4、弱符号还有一个规则,就是两个都是弱符号时,以内存占用大小较大的那个符号为准。比如未初始化的char var和long var同时存在时,链接器以实际sizeof(long)的大小来给var分配空间,实例就不讲述了,遇见这种情况需要额外小心。

小结:weak属性基本已讲述完成,其实弱符号在实际中也有很多应用。比如说在一个库里面实现某个函数,申明为弱符号,在某种情况下我们可以用自己的代码去覆盖库的实现从而重新去实现某个函数,达到定制化的目的。

二、接下去讲述alias属性,alias属性比较简单,从字面意思理解就是给符号设置一个别名,相当于取一个外号。使用方法如下:
void func(void);
void alias_func(void) __attribute__((alias("func")));  需要注意c++的符号修饰机制!

这样的意思就是函数func的别名或外号是alias_func,那么就是调用alias_func()和func()的效果是一样的,有兴趣的话可以自己写代码验证。这时需要主意func函数必须是要有定义的,否则会编译报错的。

三、最后还有一个属性是weakref活weakref("target")
__attribute__((weakref))为弱引用,请注意引用与定义的区别。weakref就是申明某个引用为弱引用,弱引用时如果需引用符号不存在也不会链接出错,而是将需要引用的符号定义为WEAK属性及0地址(跟前面的WEAK属性很相似吧)。
weakref的用法有点特别,必须要配合alias使用及必须是static定义。__attribute__((weak("target")))相当于__attribute__((weakref,alias("target"))),以下看个实例:

/*
** weakref_test.c
*/ /* 申明func_alias函数func的带弱引用的别名 */
void func(void)
{
  printf("func:%s in\n", __FUNC__);
} static void func_alias(void) __attribute__((weakref,alias("func"))); int main()
{
  func_alias(); /* 相当于调用func */
  return ;
}
编译运行,会发现实际运行的就是func函数。func_alias相当于是func的一个带有weakref属性的另一份申明,可以这样理解:void *func = func;void *func_alias = func("weakref")。
注意到前面alias属性如果func不存在时申明alias会出错,通过weakref方法,可以让func未定义就可以编译通过,使用static
void alias_func(void) __attribute__((weakref,
alias("func")))时即使func未定义也能链接通过,只不过func或alias_func的地址为0,可以去掉func的实现,验证一下
即可。

上面讲述的关于weak、alias、weakref属性都是自己的一些总结,有很多不合理之处,还望大家指出,一起探讨。
gcc版本信息:gcc version 4.4.7

gcc/g++中weak弱符号及alias别名的更多相关文章

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

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

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

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

  3. C语言中的弱符号(weak)用法及实例

    一 符号概念: 在C语言中,有强符号和弱符号,符号简单来说就是函数.变量的名字,对于全局(非局部.非static)的函数和变量,能不能重名是有一定规矩的,强.弱符号就是针对这些全局函数和变量来说的. ...

  4. Linux下gcc/g++中-I(i的大写)、-L和-l

    -I(i的大写)include头文件非标准库中存在的也不是在当前文件夹下的,需要将地址用-i(大写)包含例:-I /home/src/-L用到的函数或操作非标准库下的,需要将库存在的地址用-L包含,库 ...

  5. 在cmd中使用doskey来实现alias别名功能

            作为一枚网络工程师,经常就是面对一堆黑框框,也是就是终端.不同操作系统.不同厂家的目录,功能相同但是键入的命令又大不相同,这些差异化容易让脑子混乱.比如华为.思科.H3C.锐捷的设备, ...

  6. C++中弱符号(弱引用)的意义及实例

    今天读别人代码时看到一个“#pragma weak”,一时没明白,上网研究了一个下午终于稍微了解了一点C.C++中的“弱符号”,下面是我的理解,不正确的地方望大家指正. 本文主要从下面三个方面讲“弱符 ...

  7. C语言强、弱符号,强、弱引用

    C语言强.弱符号,强.弱引用 符号定义 在编程中我们经常碰到符号重复定义的情况,当我们在同一个作用域内重复定义同一个变量时,有时是因为误写,有时是文件之间的冲突,编译器的处理方式就是报错: redef ...

  8. gcc/g++多版本切换 (ubuntu18.04)

    使用Ubuntu18.04已经有一段时间了,在使用过程中经常需要处理不同软件的编译工作,但是这时候就遇到这样一个问题,那就是不同软件,甚至是同一个软件的不同版本都会使用不同版本的gcc/g++来进行编 ...

  9. git-bash的alias别名设置

    正常需要设置别名时,直接使用 alias gs="git status" 输入上边的命令之后,就可以使用gs(命令)代替git status(命令),这是一种设置别名简化输入,提升 ...

随机推荐

  1. SQL Server时间粒度系列----第7节日历数据表详解

    本文目录列表: 1.时间粒度有关描述 2.时间维度有关功能函数3.日历数据表 4.日历数据表数据填充 5.总结语 6.参考清单列表   时间粒度有关描述   将该系列涉及到的时间粒度以及分钟以下的粒度 ...

  2. LINQ to SQL语句(13)之开放式并发控制和事务

    Simultaneous Changes开放式并发控制 下表介绍 LINQ to SQL 文档中涉及开放式并发的术语: 术语 说明 并发 两个或更多用户同时尝试更新同一数据库行的情形. 并发冲突 两个 ...

  3. node.js操作mysql数据库之增删改查

    安装mysql模块 npm install mysql 数据库准备 mysql server所在的机器IP地址是192.168.0.108,登录账户就用root@123456 在mysql中创建tes ...

  4. .NET正则表达式基础入门(二)

    量词 正则表达式的量词用于表明前面的子表达式需要匹配的次数.阅读本章前,建议先下载我于CSDN上传的示例代码,下载无需分数,下载链接. 1.量词的一般形式 "{n}"," ...

  5. [C#] .NET4.0中使用4.5中的 async/await 功能实现异

    好东西需要分享 原文出自:http://www.itnose.net/detail/6091186.html 在.NET Framework 4.5中添加了新的异步操作库,但是在.NET Framew ...

  6. SharePoint创建web application出现“The password supplied with the username was not correct”错误的解决方法

    平台环境 Windows Server 2012 R2 Standard, SharePoint Server 2010, Microsoft SQL Server 2012 (SP1) 问题描述 在 ...

  7. 简谈asp.net下的异步加载

    具体我本身大概用的就有两种,需配合JQ. 第一种,直接通过AJAX去请求页面:例如, 1:dataType必须是html或者Text格式, 2:Type:必须是'Post'请求 3:后台Load事件必 ...

  8. jquery css事件编程 尺寸设置

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. JQuery的ajax

    JQuery-AJAX: jQuery load() 方法是简单但强大的 AJAX 方法. $(selector).load(URL,data,callback);(这三个参数可以随意设置几个) @ ...

  10. C++_系列自学课程_第_5_课_vector容器_《C++ Primer 第四版》

    再一次遇到 vector 这个单词; 每一次见到这个单词都感觉这个单词非常的 "高大上"; 数字遇到vector马上就可以360度旋转: 当 "电" 遇到vec ...