最近查看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. Switch to strategy

    namespace RefactoringLib.SwitchToStrategy.Before { public class ClientCode { public decimal Calculat ...

  2. T4 模板自动生成带注释的实体类文件 - 只需要一个 SqlSugar.dll

    生成实体就是这么简单,只要建一个T4文件和 文件夹里面放一个DLL. 使用T4模板教程 步骤1 创建T4模板 ,一定要自已新建,把T4代码复制进去,好多人因为用我现成的T4报错(原因不明) 点击添加文 ...

  3. C#~异步编程续~.net4.5主推的await&async应用

    返回目录 之前写过两篇关于异步编程的文章,详细可以进入C#~异步编程和C#~异步编程在项目中的使用 .net的各个版本都有自己主推的技术,像.NET1.1中的委托,.NET2.0中的泛型,.NET3. ...

  4. 一台主机上安装多个Tomcat

    1. 下载解压版的Tomcat,并解压两次,分别命名为Tomcat_Server_01和Tomcat_Server_02: 2. 进入Tomcat_Server_01\bin目录,编辑service文 ...

  5. Java代码优化(长期更新)

    前言 2016年3月修改,结合自己的工作和平时学习的体验重新谈一下为什么要进行代码优化.在修改之前,我的说法是这样的: 就像鲸鱼吃虾米一样,也许吃一个两个虾米对于鲸鱼来说作用不大,但是吃的虾米多了,鲸 ...

  6. 原生JS:JSON对象详解

    JSON对象 支持到IE8,旧版的IE需要Polyfill 本文参考MDN做的详细整理,方便大家参考[MDN](https://developer.mozilla.org/zh-CN/docs/Web ...

  7. iOS 多线程GCD的基本使用

    <iOS多线程简介>中提到:GCD中有2个核心概念:1.任务(执行什么操作)2.队列(用来存放任务) 那么多线程GCD的基本使用有哪些呢? 可以分以下多种情况: 1.异步函数 + 并发队列 ...

  8. iOS 开发学习资料整理(持续更新)

      “如果说我看得比别人远些,那是因为我站在巨人们的肩膀上.” ---牛顿   iOS及Mac开源项目和学习资料[超级全面] http://www.kancloud.cn/digest/ios-mac ...

  9. iOS Xcode 打包之后,不能输出日志

    现象:一个项目,之前做的好好的,后来打包,生成ipa文件之后, 再运行的时候,NSLog的日志都不输出了. 解决方案: 在模式选择里面,里面包含:“Debug”.“Release”两种,设置“Debu ...

  10. sharepoint2013用场管理员进行文档库的爬网提示"没有权限,拒绝"的解决方法

    爬网提示被拒绝,场管理员明明可以打开那个站点的,我初步怀疑是:环回请求(LoopbackRequest)导致的 解决方法就是修改环回问题.修改注册表 具体操作方法: http://www.c-shar ...