C语言中的强弱符号

文章目录

      • 一、基本定义
      • 二、链接过程中的行为
      • 三、应用场景
      • 四、强弱符号示例1
      • 五、稍有难度示例2

在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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/946934.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据仓库建设方案和经验总结

在做数据集成的过程中&#xff0c;往往第二步的需求就是建设数仓由于数据分散在不同的存储环境或数据库中&#xff0c;对于新业务需求的开发需要人工先从不同的数据库中同步、集中、合并等处理&#xff0c;造成资源和人力的浪费。同时&#xff0c;目前的系统架构&#xff0c;无…

SAP SD学习笔记24 - 赠品的两种形式 - 内增Bonus数量、外增Bonus数量

上一章讲了无偿出荷的内容。 SAP SD学习笔记23 - 无偿出荷&#xff08;免费交货&#xff09;与继续无偿出荷&#xff08;继续免费交货&#xff09;-CSDN博客 本章继续将SAP中赠品的两种形式&#xff1a; - 内增Bonus数量&#xff1a;Bonus数量包含在总数量当中&#xff0c;比…

【JVM】JVM自学笔记(类加载子系统、运行时数据区、执行引擎)

JVM自学笔记 引言总结JVM跨平台JVM组成部分类加载子系统运行时数据区程序计数器虚拟机栈本地方法栈堆 执行引擎垃圾回收 引言 主要内容为学习b站视频后的笔记部分个人总结。原视频链接为&#xff1a;【【JVM极简教程】2小时快速学会JVM&#xff0c;史上用时最短&#xff0c;效…

丢弃法hhhh

一个好的模型需要对输入数据的扰动鲁棒 丢弃法&#xff1a;在层之间加入噪音&#xff0c;等同于加入正则 h2和h5变成0了 dropout一般作用在全连接隐藏层的输出上 Q&A dropout随机置零对求梯度和求反向传播的影响是什么&#xff1f;为0 dropout属于超参数 dropout固定随…

深入Android架构(从线程到AIDL)_06 短程通信 vs. 远程通信

目录 7、 短程通信 vs. 远程通信 範例&#xff1a; 短程通信 撰写步骤 範例&#xff1a; 遠程通信 7、 短程通信 vs. 远程通信 範例&#xff1a; 短程通信 首先出现ac01画面&#xff0c;立即启动myService&#xff0c;定时连续传来数字&#xff0c;如下&#xff1a;由于定…

进销存软件数据库设计

设置 system_config 系统参数配置pricing_policy 价格策略&#xff08;销售采购价格取数优先级&#xff09;code_rule 编码规则account_book 账套checkout 结账admin 管理员role 角色menu 菜单menu_role 角色菜单merchant 商户merchant_menu 商户菜单merchant_user 商户用户资料…

[文献阅读]ReAct: Synergizing Reasoning and Acting in Language Models

文章目录 摘要Abstract:思考与行为协同化Reason(Chain of thought)ReAct ReAct如何协同推理 响应Action&#xff08;动作空间&#xff09;协同推理 结果总结 摘要 ReAct: Synergizing Reasoning and Acting in Language Models [2210.03629] ReAct: Synergizing Reasoning an…

antd-vue - - - - - a-date-picker限制选择范围

antd-vue - - - - - a-date-picker限制选择范围 1. 效果展示2. 代码展示 1. 效果展示 如图&#xff1a;限制选择范围为 今年 & 去年 的 月份. 2. 代码展示 <template><a-date-picker:disabledDate"disabledDate"picker"month"/> &l…

OceanBase到MySQL实时同步方案

概述 本方案基于OceanBase Binlog服务&#xff0c;采用数据库实时复制软件Beedup订阅捕获OceanBase数据库的Binlog事件&#xff0c;复制软件将Binlog事件还原为MySQL支持的DML或DDL&#xff0c;然后交由MySQL数据库执行。 配置Binlog任务 启用OceanBase Binlog服务&#xff…

[QT]控件的核心属性

一、控件的核心属性 1.enable属性 表示一个控件是否可用&#xff0c;可以用isEnabled()接口获取到当前控件的可用状态&#xff0c;同时来提供了setEnabled()接口设置控件是否可用&#xff0c;传递的参数为true和false。 isEnabled(); setEnabled(bool); Demo&#xff1a;通过一…

DRAM 的类型

DRAM&#xff08;Dynamic Random Access Memory&#xff09;&#xff0c;即动态随机存取存储器&#xff0c;是现代计算机系统中不可或缺的存储组件之一。 根据市场情况主要分为以下几种&#xff1a; 一、SDRAM&#xff08;Synchronous Dynamic Random Access Memory&#xff0…

虚拟机中的时统卡功能和性能调优

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

创新驱动智能运维,护航军工新时代

随着数字化转型的加速推进&#xff0c;智能运维技术在各行业的重要性愈加凸显。军工行业作为国家安全和技术创新的核心&#xff0c;对运维解决方案的安全性、可靠性及自主可控性提出了严格要求。美信时代科技有限公司以自主创新为基础&#xff0c;推出监控易一体化智能运维管理…

《计算机网络》(B)复习

目录 一、问答题测试 1.论述具有五层协议的网络体系结构的要点&#xff0c;包括各层的主要功能。 2.物理层的接口有哪几个方面的特性&#xff1f;各包含些什么内容&#xff1f; 3.小明想要访问淘宝&#xff0c;当他打开浏览器输入www.taobao.com浏览淘宝的 过程是什么&#…

如何配置【Docker镜像】加速器+【Docker镜像】的使用

一、配置Docker镜像加速器 1. 安装/升级容器引擎客户端​ 推荐安装1.11.2以上版本的容器引擎客户端 2. 配置镜像加速器​ 针对容器引擎客户端版本大于1.11.2的用户 以root用户登录容器引擎所在的虚拟机 修改 "/etc/docker/daemon.json" 文件&#xff08;如果没有…

logback之自定义过滤器

logback有两种过滤器&#xff0c;一种是context中的过滤器叫TurboFilter&#xff0c;是一个全局的过滤器&#xff0c;会影响所有的日志记录。另一种是Appender中的过滤器&#xff0c;只对所在的append有效。两者大同小异&#xff0c;这里我们以Appender的过滤器为例。 &#x…

springboot+vue实现SSE服务器发送事件

思路 一个基于订阅发布机制的SSE事件。客户端可以请求订阅api&#xff08;携带客户端id&#xff09;&#xff0c;与服务器建立SSE链接&#xff1b;后续服务器需要推送消息到客户端时&#xff0c;再根据客户端id从已建立链接的会话中找到目标客户端&#xff0c;将消息推送出去。…

使用XGBoost算法进行机器学习任务:从理论到实践

目录 使用XGBoost算法进行机器学习任务&#xff1a;从理论到实践引言1. XGBoost算法简介2. XGBoost的数学原理3. 环境准备与数据集介绍3.1 环境准备3.2 数据集介绍 4. XGBoost的PyTorch实现4.1 数据预处理4.2 XGBoost模型定义4.3 模型训练与评估 5. 结果分析与可视化5.1 绘制损…

NeurIPS 2024 | 像素级LLM实现图像视频理解、生成、分割和编辑大统一(昆仑万维等)

Accepted by NeurIPS 2024 文章链接&#xff1a;https://arxiv.org/pdf/2412.19806 项目链接&#xff1a;https://vitron-llm.github.io/ Github链接&#xff1a;https://github.com/SkyworkAI/Vitron 亮点直击 首次提出了一种通用的视觉多模态大语言模型&#xff08;MLLM&…

P8打卡——YOLOv5-C3模块实现天气识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 1.检查GPU import torch import torch.nn as nn import torchvision.transforms as transforms import torchvision from torchvision import transforms, dat…