我们在编写代码的过程中经常会遇到一种叫做符号重复定义(Multiple Definition)的错误,这是因为在多个源文件中定义了名字相同的全局变量,并且都将它们初始化了。

例如,在 a.c 中定义了全局变量 global:

int global = 10;

在 b.c 中又对 global 进行了定义:

int global = 20;

那么在链接时就会出现下面的错误:

b.o: multiple definition of `global'
a.o: first defined here

这种符号的定义可以被称为强符号。

在C语言中,编译器默认函数和初始化了的全局变量为强符号(Strong Symbol),未初始化的全局变量为弱符号(Weak Symbol)。强符号之所以强,是因为它们拥有确切的数据,变量有值,函数有函数体;弱符号之所以弱,是因为它们还未被初始化,没有确切的数据。

链接器会按照如下的规则处理被多次定义的强符号和弱符号:
1) 不允许强符号被多次定义,也即不同的目标文件中不能有同名的强符号;如果有多个强符号,那么链接器会报符号重复定义错误。

2) 如果一个符号在某个目标文件中是强符号,在其他文件中是弱符号,那么选择强符号。

3) 如果一个符号在所有的目标文件中都是弱符号,那么选择其中占用空间最大的一个。

比如目标文件 a.o 定义全局变量 global 为 int 类型,占用4个字节,目标文件 b.o 定义 global 为 double 类型,占用8个字节,那么被链接后,符号 global 占用8个字节。请尽量不要使用多个不同类型的弱符号,否则有时候很难发现程序错误。

在 GCC 中,可以通过__attribute__((weak))来强制定义任何一个符号为弱符号。假设现在有下面的一段代码:

extern int ext;
int weak1;
int strong = 100;
__attribute__((weak)) weak2 = 2;
int main(){return 0;
}

weak1 和 weak2 是弱符号,strong 和 main 是强符号,而 ext 既非强符号也非弱符号,它是一个对外部变量的引用(使用)。

为了加深理解,我们不妨再来看一个多文件编程的例子。

main.c 源码:

#include <stdio.h>
//弱符号
__attribute__((weak)) int a = 20;
__attribute__((weak)) void func(){printf("C Language\n");
}
int main(){printf("a = %d\n", a);func();return 0;
}

module.c 源码:

#include <stdio.h>
//强符号
int a = 9999;
void func(){printf("c.biancheng.net\n");
}

在 GCC 中,使用下面的命令来运行程序:

$gcc main.c module.c
$./a.out
a = 9999
c.biancheng.net

在 main.c 中,a 和 func 都是弱符号,在 module.c 中,a 和 func 都是强符号,强符号会覆盖弱符号,所以链接器最终会使用 module.c 中的符号,输出结果也印证了这一点。

需要注意的是,__attribute__((weak))只对链接器有效,对编译器不起作用,编译器不区分强符号和弱符号,只要在一个源文件中定义两个相同的符号,不管它们是强是弱,都会报“重复定义”错误。请看下面代码:

#include <stdio.h>
__attribute__((weak)) int a = 20;
int a = 9999;
int main(){printf("a = %d\n", a);return 0;
}

这段代码在编译阶段就会报错,编译器会认为变量 a 被定义了两次,属于重复定义。

弱符号对于库来说十分有用,我们在开发库时,可以将某些符号定义为弱符号,这样就能够被用户定义的强符号覆盖,从而使得程序可以使用自定义版本的函数,增加了很大的灵活性。

本文转自:强符号和弱符号

转载于:https://www.cnblogs.com/yongdaimi/p/8084634.html

13.强符号和弱符号相关推荐

  1. 【嵌入式】C语言高级编程-强符号和弱符号(09)

    00. 目录 文章目录 00. 目录 01. weak属性 02. 变量强符号和弱符号 03. 函数强符号和弱符号 04. 弱符号的作用 05. alias属性 06. 附录 01. weak属性 G ...

  2. 新手小心:c语言的强符号和弱符号

    声明:下面的实例全部在linux下尝试,window下未尝试.有兴趣者可以试一下.文章针c初学者. c语言的强符号和弱符号是c初学者经常容易犯错的地方.而且很多时候,特别是多人配合开发的程序,它引起的 ...

  3. 【C语言】强符号与弱符号

    目录 一.先说结论 二.当attribute修饰符号的引用/声明时--不做链接 2.1.变量声明 2.2.函数声明 三.链接.o文件 3.1.函数 3.1.1.多个强符号 3.1.2.一个强符号多个弱 ...

  4. 【C语言】强符号和弱符号

    1.强符号.弱符号定义 编译器在编译源程序时,无论你是变量名.函数名,在它眼里,都是一个符号而已,用来表征一个地址.编译器会将这些符号集中,存放到一个叫符号表的 section 中. 那么对于两个.c ...

  5. C语言中的强符号和弱符号

    一.强弱符号 强弱符号针对的是处于同一工程下在不同源文件下定义的全局变量符号,链接器只处理global的符号而不处理local的符号.链接的核心是符号的重定位,在符号引用的地方找到符号定义的地方,包括 ...

  6. C语言 强符号与弱符号

    对于C语言来说,编译器默认函数和初始化的全局变量为强符号,未初始化的全局变量为弱符号(C++并没有将未初始化的全局符号视为弱符号).可以通过GCC的"__ attribute ((weak) ...

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

    注意,强符号和弱符号都是针对定义来说的,不是针对符号的引用. 一.概述 在C语言中,函数和初始化的全局变量(包括显示初始化为0)是强符号,未初始化的全局变量是弱符号. 对于它们,下列三条规则使用: ① ...

  8. 浅谈一下嵌入式中的强符号和弱符号

    __attribute__  是一个编译器指令,其实是 GNU C 的一种机制,本质是一个编译器的指令,在声明的时候可以提供一些属性,在编译阶段起作用,来做多样化的错误检查和高级优化. 用于在 C.C ...

  9. c语言弱符号与函数指针,浅谈C语言中的强符号、弱符号、强引用和弱引用【转】...

    首先我表示很悲剧,在看<程序员的自我修养--链接.装载与库>之前我竟不知道C有强符号.弱符号.强引用和弱引用.在看到3.5.5节弱符号和强符号时,我感觉有些困惑,所以写下此篇,希望能和同样 ...

最新文章

  1. Windows下的bat文件的@echo off 作用
  2. 【Java】7.1 与用户互动 7.2 系统相关
  3. 《C++语言基础》程序阅读——和对象找感觉
  4. pyspark模块介绍
  5. 是时候开始用C#快速开发移动应用了
  6. java8 新特性之流式数据处理_Java8新特性 - 集合流式编程 - 最终操作
  7. 计算机基础的函数公式,大学计算机基础 excle 公式与函数
  8. SQL点滴系列之删除数据(五)
  9. 第2讲 ZF2.4 最新框架搭建
  10. qq批量登录软件_QQ账号永久冻结
  11. 三菱plc232通讯实例_三菱PLC编程实例与通讯
  12. 为什么说python是世界上最好的语言-《权力的游戏》告诉你,为啥 Python 是世上最好的语言...
  13. 神解释:为什么程序员怕改需求?
  14. eNSP路由器接口地址通过DHCP分配
  15. 使用GNN求解组合优化问题
  16. 艾孜尔江_Unity 3D入门常用函数用法及案例概要【干货】
  17. 明日之后各个服务器的信息,明日之后三个字的和四个字的区什么不同 服务器区别详解...
  18. git及gitlab的安装和使用
  19. MySQL Java JDBC
  20. 现在有很多第三方的SDK来做直播,那么我们改选择哪一种?

热门文章

  1. 15_采用Pull解析器解析和生成XML内容
  2. 包装设计中文字字体的logo设计要注意什么
  3. java并发编程实战-第三章-对象的共享
  4. MySQL/sqlserver查询in操作 查询结果按in集合顺序显示
  5. PHP监測memcache服务端的执行状况
  6. 如何找出MySQL数据库中的低效SQL语句
  7. php变量作用域(花括号、global、闭包)
  8. 关于软件版本命名的方法
  9. 给要学习.NET(c#语言)的新手一些学习方法
  10. 2010-04-25 搞定aftr