最近查看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. 【原创】Kafka console consumer源代码分析(二)

    我们继续讨论console consumer的实现原理,本篇着重探讨ZookeeperConsumerConnector的使用,即后续所有的内容都由下面这条语句而起: val connector = ...

  2. Cocos2dx实现光影效果的两种方式

    Shader 和 RenderTexture 先贴上两张效果图 (Shader) (RenderTexture) 说一下实现的原因,因为项目中需要夜景,光影的效果.最初想到使用Shader来实现.实现 ...

  3. [Excel] Worksheet.PasteSpecial

    PasteSpecial(Format, Link, DisplayAsIcon, IconFileName, IconIndex, IconLabel, NoHTMLFormatting) 1. F ...

  4. hostingEnvironment与宿主环境

    定义用来控制应用程序宿主环境的行为的配置设置. 配置如下 <hostingEnvironment idleTimeout="HH:MM:SS" shadowCopyBinAs ...

  5. EntityFrame Work 6 Code First 配置字段为varchar 类型

    EntityFrame Work 6 配置字符串属性是否支持Unicode 内容 默认情况下,字符串为Unicode(SQLServer 中的nvarchar).您可以使用IsUnicode 方法指定 ...

  6. java Io缓冲区复制文件

    //直接写代码了  类和包自己导入创建 ,手打很累的 public static void main(String args[]){ FileReader fr=null;   //文件输入流 Fil ...

  7. Sublime Text使用配置介绍

    这篇文章很多内容都是来源自网络,发布这里当作自己留个底,以后不用到处去找 对于文本编辑器,我用过notepad2.notepad++.Editplus.UltraEdit.Vim.TextPad,都没 ...

  8. JavaScript类属性

    对象的类属性(class attribute)是一个字符串,用以表示对象的类型信息.ECMAScript3和ECMAScript5都未提供设置这个属性的方法,并只有一个间接的方法可以查询它.默认的to ...

  9. CSS:CSS样式表及选择器优先级总结

    我们在写网页的时候经常会遇到同一个HTML文件,使用了外部样式.内部样式以及内联样式,那么如果发生冲突时浏览器是怎么抉择的呢? 也会遇到这样的情况,在样式表中,对同一个HTML元素,我们有可能既用到了 ...

  10. 轻松掌握:JavaScript组合模式

    组合模式 组合模式:将一组对象组合成树形结构,并统一对待组合对象和叶对象,忽略它们之间的不同(因为叶对象也可以也可以包含叶对象而成为组合对象),组合模式中的对象只能是一对多的关系,不能出现多对一. 基 ...