C语言中的强弱符号

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


在C语言中,强弱符号是与链接过程相关的重要概念,C++中不存在强弱符号,以下是对它们的详细讲解:

一、基本定义

  1. 强符号
    强符号通常是指在编译单元(一般是一个源文件,即 .c 文件)中定义的全局变量或者函数。例如,在一个 .c 文件中定义了如下全局变量:
int global_variable = 10;  // 这是一个强符号的全局变量定义

或者定义了这样的函数:

int my_function(int a) {
    return a + 1;
}  // 这是一个强符号的函数定义

强符号代表了一个确切的、具有唯一内存地址的实体,在链接阶段会参与到最终可执行文件的符号整合过程中。

  1. 弱符号
    弱符号相对特殊,它也是一种全局变量或者函数的表示形式,但允许在链接阶段被其他同名的强符号覆盖。在一些特定的应用场景中,比如在模块开发中,可能一个模块提供了某个功能的弱符号实现,而另一个模块可以用更强的实现来替换它。一般未初始化的普通全局变量 int g_val;

在常见的GCC编译器中,可以使用 __attribute__((weak)) 语法来声明一个弱符号。例如,声明一个弱符号的全局变量可以这样做:

int __attribute__((weak)) weak_variable = 5;  // 这是一个弱符号的全局变量声明及定义

对于函数,同样可以定义为弱符号形式:

int __attribute__((weak)) weak_function(int a) {
    return a;
}

二、链接过程中的行为

  1. 同名强符号冲突
    当链接器在处理多个编译单元时,如果发现存在同名的强符号(比如两个不同的 .c 文件都定义了一个名为 same_name_variable 的全局变量且都是强符号形式),那么链接器会报错,提示符号重复定义(因为强符号都期望有唯一确定的定义进入最终可执行文件)。例如:
    文件 file1.c 中有:
int same_name_variable = 10;

文件 file2.c 中有:

int same_name_variable = 20;

在链接这两个文件生成可执行文件时,链接器会指出 same_name_variable 重复定义的错误,无法继续生成可执行文件。

  1. 强符号与弱符号并存
    如果一个符号既有强符号定义又有弱符号定义,在链接阶段,最终会使用强符号。例如,文件 file1.c 定义了强符号的全局变量:
int combined_variable = 10;

而文件 file2.c 定义了同名的弱符号全局变量:

int __attribute__((weak)) combined_variable = 20;

在链接这两个文件后,最终可执行文件中使用的是 file1.c 中定义的强符号对应的 combined_variable 的值(也就是 10),弱符号的定义被忽略了。

  1. 多个弱符号情况
    当存在多个同名的弱符号时,链接器会选择其中一个(不同编译器或者不同链接器的具体选择策略可能略有差异,但一般是按照某种顺序选取,比如先遇到的那个等)一般会选择内存占用交大的那个,并且不会报错。例如,文件 file1.c 中有:
int __attribute__((weak)) multi_weak_variable = 10;

文件 file2.c 中有:

int __attribute__((weak)) multi_weak_variable = 20;

链接器可能会选择 file1.c 中定义的那个弱符号(假设按照遇到顺序选取等情况),并将其纳入最终可执行文件中,当然这种情况需要开发者根据具体需求谨慎使用,避免出现不符合预期的结果。

三、应用场景

  1. 库函数的可选实现
    在一些库的开发中,可以将某些函数定义为弱符号。比如一个设备驱动库,对于某个特定功能的函数,在不同的硬件平台上可能有不同的实现方式,开发者可以将基础的、通用的实现定义为弱符号,然后当针对具体硬件平台编译时,如果有更适配的强符号函数实现(比如针对该硬件专门优化过的函数),就可以覆盖弱符号对应的函数,这样能增强库的灵活性和可扩展性。

  2. 插件式开发
    在插件式的软件架构中,主程序可以定义一些弱符号的函数或者变量,插件模块可以根据自身需求提供强符号的对应实现来覆盖主程序中的弱符号,从而实现特定的功能扩展,同时又保证了在没有插件覆盖时主程序也能有基本的、默认的运行状态。

总之,强弱符号在C语言中为程序的模块化开发、不同实现的灵活替换等方面提供了有效的机制,合理运用它们可以提升代码的可维护性和可扩展性。

四、强弱符号示例1

a.c


int g_data1;

void fun()
{
	g_data1 = 20;
}

main.c

#include<stdio.h>
extern void fun();

int g_data1=1;
int main()
{
	fun();
	printf("%d\n" , g_data1);
	return 0;
}

打印结果 20
在这里插入图片描述
分析如下
1、编译,编译阶段a.c fun()函数,g_data1 = 20;//往g_data1所在的内存空间写入数据20 , 写多大呢,因为编译阶段能看到本文件内g_data1为int 型 , 所以写四个字节;
2、链接阶段,因为a.c 里 g_data1只有声明,没有定义,所以是弱符号,普通的、全局的、未初始化的变量,在编译阶段生成符号是放在一个特定的区域,在linux里是COM块 , 只有在链接后,进行强弱符号选择后,才会把符号放进.bss或者.data段 , 若符号在链接阶段会重新进行强弱符号的选择,最终选择强符号,也就是main.c里的g_data1 , 相当于往main.c的g_data1里写进20 ;
3、main.c编译阶段printf打印的就是强符号,所以打印出来就是20

五、稍有难度示例2

main.c

#include<stdio.h>
extern void fun();

char  gdata1=10;
char  gdata2 = 10;
int main()
{
	fun();
	printf("%d , %d\n" , gdata1 , gdata2);
	return 0;
}


a.c


int gdata1;

void fun()
{
	gdata1 = 20;
}

在这里插入图片描述
分析如下:
1、编译阶段,a.c gdata1为弱符号,函数内gdata1 = 20;编译为往gdata1所在的内存空间写入20,因为编译阶段智能看到本文件内的符号,此时gdata1为Int 型 , 所以写入四个字节;
2、main.c在链接时,开始强弱符号选择,选择了强符号,强符号为char类型的,那就糟糕了,因为在编译阶段就已经确定了指令了,往gdata1所在内存写入四个字节,写入数据20,如下图,从gdata1开始往后四个字节写入20也解释0x 00 00 00 14 , 把gdata2的数据也给覆盖了,原本是10 , 0a,覆盖后变成了0 , 所以打印出来就是 20 ,0

在这里插入图片描述
在这里插入图片描述

C语言弱符号与弱引用技术解析 在C语言开发中,符号处理是编译链接过程中的核心概念。弱符号(weak symbol)通过`__attribute__((weak))`属性标记,允许符号被重定义,这种机制在驱动开发和多平台适配中尤为重要。其技术价值体现在提供默认实现的同时支持灵活覆盖,典型应用于硬件抽象层设计。弱引用(weak reference)则通过`__attribute__((weakref))`声明,实现符号的延迟绑定,常用于插件式架构开发。这两种技术配合使用,能有效解决跨平台开发中的API差异问题,如STM32不同库(HAL/L 阅读详情

相关推荐

C语言中的强符号和弱符号介绍

之前在extern “C” 用法详解中已经提到过符号的概念,它是编译器对变量和函数的一种标记,编译器对C和C++代码在生产符号时规则也是不一样的,符号除了本身名字的区别外,还有强符号和弱符号之分 我们先看一段简单的代码 代码如下: /* test.c */  void hello();  int main()  {      hello();      return 0;  }  很显然,这段代码是没法链接通过的,它会报错undefined reference to hello,说的是hello未定义,因为这里我们只声明了函数hello,而没有定义它。但是我们把代码稍作修改如下

详解 C 语言中的弱符号与弱引用

详解 C 语言中的弱符号与弱引用;一文读懂 C 语言中的__attribute__((weak)) 与 __attribute__ ((weakref())的用法与含义。

物联网老王的博客,公众号同名 8693

别再乱装了!Win10下NVIDIA显卡驱动、CUDA 11.0和cuDNN 8.0.5保姆级配置指南(含版本匹配避坑)

本文提供Win10下NVIDIA显卡驱动、CUDA 11.0和cuDNN 8.0.5的保姆级配置指南,详细解析版本匹配逻辑与安装步骤。从驱动选择到环境变量配置,再到框架测试,手把手教你避开常见坑点,确保深度学习环境一次配置成功。特别强调版本匹配的重要性,帮助开发者高效搭建GPU开发环境。

weixin_30600197的博客 307

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

强符号:函数名、初始化的全局变量名; 弱符号:未初始化的全局变量名。

ypf_bendan的博客 2610

Bulk / Smart-seq2数据分析一般流程

Bulk RNA-seq(RNA-Seq of bulk samples)是一种RNA-Seq技术应用,它是通过将整个组织或细胞群体的RNA提取并混合,进行高通量测序来分析基因表达的技术。转录本定量结果可以用于后续的差异表达分析和聚类分析。功能注释和富集分析:对差异表达基因进行功能注释和富集分析,以帮助理解差异表达基因的功能和调控网络,从而获得对研究样品的更深入的理解。数据可视化:最后,将聚类分析的结果进行可视化,可以使用常见的数据可视化工具,如ggplot2、Plotly等,来帮助用户更好地理解数据。

weixin_54519672的博客 5353

Proxmox VE安装卡顿深度解析:显卡驱动与BIOS设置的黄金法则

本文深度解析Proxmox VE安装卡顿的根本原因,指出显卡驱动与BIOS设置是两大关键因素。文章详细阐述了如何通过添加`nomodeset`内核参数解决显卡兼容性问题,并提供了针对不同主板品牌的BIOS显卡优先级设置黄金法则。同时,还分享了从预处理到高级调试的完整实战排查流程,帮助用户从源头杜绝安装卡顿,确保PVE系统顺利部署。

weixin_29278805的博客 472

C语言中弱符号与弱引用的实际应用

在编码过程中,我们经常遇到符号重定义的错误。这就是符号重复定义导致的,再往细里面说,是在同一作用域内符号冲突。我们知道变量是由作用域和生命周期概念的。例1:main.cint main()return 0;strong.c则会报重定义错误。因为在main.c 和strong.c 文件中,整型变量strong是全局变量,它们的作用域都是跨文件的。若是在不同的作用域,即使相同变量名,也不会报错。

点滴路程 1418

Mask2former自定义数据集实现滑坡语义分割

先介绍一下这次用的数据集:Bijie Landslide Dataset,是武汉大学在Triplesat卫星上裁剪的数据集,包含770张滑坡(image、mask、dem、边界坐标txt)和2003张非滑坡数据(dem、image)。直接在ade20k修改,按照路径和设置将预处理数据放好,该步骤很快就能结束,打开的图片是全黑的,因为0和1在图片上肉眼较难区分。bijie的数据集可以直接使用,接下去的步骤是1、预处理数据。配置文件修改训练类别和训练类型,由于我们分割的是滑坡,所以进行语义分割。

weixin_57812838的博客 2217

C语言 强弱符号,强弱引用

首先我表示很悲剧,在看《程序员的自我修养–链接、装载与库》之前我竟不知道C有强符号、弱符号、强引用和弱引用。在看到3.5.5节弱符号和强符号时,我感觉有些困惑,所以写下此篇,希望能和同样感觉的朋友交流也希望高人指点。   首先我们看一下书中关于它们的定义。   引入场景:(1)文件A中定义并初始化变量i(int i = 1), 文件B中定义并初始化变量i(int i = 2)。编译链接A、B时会报错

mqqiao的博客 1795

STM32开发 -- 4G模块开发详解(1)

这部分一直再看,资料都已经整理好了,但是一直没有汇总。接下来就详细的看一下,GSM这部分是怎么实现的。

不积跬步,无以至千里 5万+

第七节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - 用户管理(上)

本节的内容是用户管理,后端Python代码的实现。

cuiwin的专栏 781

C语言强弱符号的概念及规则

在c语言中,函数和初始化的全局变量是强符号,未初始化的全局变量时弱符号。强符号和弱符号的定义是连接器用来处理多重定义符号的,它的规则是:   不允许多个强符号;   如果一个强符号和一个弱符号,这选择强符号;   如果多个弱符号,则任意选一个。

niukailun523的专栏 931

AFSim2.9.0学习笔记 —— 2、AFSim的Wizard软件概述(ArkSIM集成开发环境 (IDE))

AFSim2.9.0学习笔记 —— 2、AFSim的Wizard软件详述(ArkSIM集成开发环境 (IDE))

923

浅谈C语言中的强符号、弱符号、强引用和弱引用【转】

转自:http://www.jb51.net/article/56924.htm 首先我表示很悲剧,在看《程序员的自我修养--链接、装载与库》之前我竟不知道C有强符号、弱符号、强引用和弱引用。在看到3.5.5节弱符号和强符号时,我感觉有些困惑,所以写下此篇,希望能和同样感觉的朋友交流也希望高人指点。   首先我们看一下书中关于它们的定义。   引入场景:(1)文件A中定义并初始化变量i(in...

weixin_33895604的博客 129

RK3588芯片USB OTG模式切换:Device到Host的驱动奥秘之旅

摘要:本文详细介绍了RK3588芯片USB OTG模式从Device到Host的完整驱动流程,包括硬件电路设计、内核驱动配置、模式切换机制及验证方法。RK3588芯片凭借强大的性能和灵活的USB OTG特性,在工业控制、智能家居等领域具有广泛应用前景。文章重点分析了Type-C接口设计、USBPHY芯片选型、Linux内核模块配置等关键技术要点,并提供了模式切换脚本使用方法和常见问题解决方案,为开发者实现RK3588 USB OTG功能提供了全面指导。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 743

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

简图记录-C语言 强符号与弱符号

简图记录学习~    C语言在编译过程函数和变量都按符号的方式记录,常在编译链接时发生符号重复定义、符号无定义等错误,一不小心还会出现强弱符号覆盖这类不易察觉的隐含问题。以下部分内容来自《程序员的自我修改》,非常好的一本关于编译链接和库的书籍。一、概念    符号:编译器在链接不同目标文件时,需要处理各个文件之间的定义、调用和访问关系,编译器将函数和变量等都统称为符号,每个elf文件都有一个符号段...

runafterhit的博客 709

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

C语言的弱符号与强符号

c语言的强符号和弱符号是c初学者经常容易犯错的地方。而且很多时候,特别是多人配合开发的程序,它引起的问题往往非常行为怪异而且难以定位。   什么是强符号和弱符号?   在c语言中,函数和初始化的全局变量是强符号,未初始化的全局变量时弱符号。强符号和弱符号的定义是连接器用来处理多重定义符号的,它的规则是:   不允许多个强符号;   如果一个强符号和一个弱符号,这选择强符号;

SdustLiYang的专栏 754

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

C之(6)强弱符号引用

如果在代码里面重复定义变量、全局函数,那么编译器就会报出的错误。注意,这里针对同一作用域才会有冲突。一种是语法块作用域,即大括号括起的语句块,其变量都是局部作用域。另外就是文件作用域,这个和常说的全局作用域很像,但是仅限于C源文件,需要注意,C的源文件是单独编译的。再就是全局作用域,即其符号作用域为整个二进制文件。那这里重点关注重定义问题,就是全局作用域。int a;....弱符号的机制是用来定义某个桩函数,适合于用户自定义新函数来覆盖原有的功能。

梅花香自苦寒来,宝剑锋从磨砺出。 726

强符号与弱符号

文章目录强符号不允许多次定义强弱可以共存都是弱符号 简而言之,在 C 语言中,函数和初始化的全局变量(包括显示初始化为 0)是强符号,未初始化的全局变量是弱符号。 在链接器进行链接的时候,有下面的规则 强符号不允许多次定义(即不同的目标文件中不能有同名的强符号) 强弱可以共存,共存时,强覆盖弱 都是弱符号时,选择占用空间最大的; 我们举例子说明。 强符号不允许多次定义 针对 1,代码片段是: // a.c int tea = 2; // strong // b.c int tea = 1; // s

车子(chezi) 1302

强符号弱符号引起的编译问题

第一篇文章: http://www.searchtb.com/2013/03/compile_problems_about_strong_weak_symbols.html 第二篇文章: http://www.byvoid.com/zhs/blog/c-global-variables-in-multiple-files 首先看一段代码 func.c int buf = 0; v

renwotao2009的专栏 2078

简述C语言中的符号和链接库

linux-C的符号和elf文件结构

qq_42716357的博客 280

静态链接之符号解析

符号解析 符号解析的目的就是将各个模块(模块之中与模块之间)引用与定义联系起来 首先,什么是符号?符号包括 函数(static和非static) 全局变量 外部变量 静态局部变量 static属性 先简单说明一下static属性,对于全局变量和函数来说,使用static是将它们的“可见”范围限制在了本模块,即它们可以被合法引用的地方仅仅限与定义它们的这个模块(文件); ...

zycde优快云的博客 1228

别再乱用全局变量了!从链接器视角看C语言强/弱符号的那些坑

本文从链接器视角深入解析C语言全局变量中强/弱符号的潜在陷阱,揭示符号表机制如何导致运行时错误。通过分析符号解析规则和实际案例,提供防御性编程技巧和调试工具链,帮助开发者避免常见的全局变量误用问题,提升代码健壮性。

weixin_42562079的博客 360

c程序设计语言 linux公社,C程序设计语言--全局变量的认识

这个项目里我们定义了四个全局变量,t.h头文件定义了一个整型a,main.c里定义了两个整型b和c并且未初始化,foo.c里定义了一个初始化了的结构体,还定义了一个main的函数指针变量。由于C语言每个源文件单独编译,所以t.h分别包含了两次,所以int a就被定义了两次。两个源文件里变量b和函数指针变量main被重复定义了,实际上可以看做代码段的地址。但编译器并未报错,只给出一条警告:/usr/...

weixin_39765695的博客 216

强弱符号

#include<stdio.h> short a = 10;//强符号 short b = 20; int main() { Func(); printf("a: %d\n",a); printf("b: %d\n",b); return 0 } int a;//弱符号 void Func() { a = 100; }//生成指令:mov dword ptr[a],...

IWantPlayYasuo的博客 861
上一篇: C++类对象内存对齐方式
下一篇: 编译链接全过程
越甲八千
博客等级 码龄11年 2959粉丝 553原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值