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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring中的IOC是什么,优缺点有哪些?

目录 IOC的核心概念 IOC的优点 IOC的缺点 使用场景说明 总结 IOC&#xff08;控制反转&#xff09;是一种设计思想&#xff0c;用于实现低耦合、高内聚的软件架构。它通过将对象的创建和依赖管理交给外部容器来实现&#xff0c;从而减少对象之间的直接依赖关系。 IOC的核…

【网络协议】开放式最短路径优先协议OSPF详解(一)

OSPF 是为取代 RIP 而开发的一种无类别的链路状态路由协议&#xff0c;它通过使用区域划分以实现更好的可扩展性。 文章目录 链路状态路由协议OSPF 的工作原理OSPF 数据包类型Dijkstra算法、管理距离与度量值OSPF的管理距离OSPF的度量值 链路状态路由协议的优势拓扑结构路由器O…

鸿蒙HarmonyOS开发:拨打电话、短信服务、网络搜索、蜂窝数据、SIM卡管理、observer订阅管理

文章目录 一、call模块&#xff08;拨打电话&#xff09;1、使用makeCall拨打电话2、获取当前通话状态3、判断是否存在通话4、检查当前设备是否具备语音通话能力 二、sms模块&#xff08;短信服务&#xff09;1、创建短信2、发送短信 三、radio模块&#xff08;网络搜索&#x…

Docker学习相关笔记,持续更新

如何推送到Docker Hub仓库 在Docker Hub新建一个仓库&#xff0c;我的用户名是 leilifengxingmw&#xff0c;我建的仓库名是 hello_world。 在本地的仓库构建镜像&#xff0c;注意要加上用户名 docker build -t leilifengxingmw/hello_world:v1 .构建好以后&#xff0c;本地会…

2024年12月 Scratch 图形化(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch图形化等级考试(1~4级)全部真题・点这里 一、单选题(共25题,共50分) 第 1 题 点击下列哪个按钮,可以将红框处的程序放大?( ) A. B. C.

向 SwiftUI 视图注入 managedObjectContext 环境变量导致 Xcode 预览(Preview)崩溃的解决

问题现象 从 SwiftUI 诞生到现在,我们这些秃头码农们早已都习惯了在 Xcode 预览中调试 App 界面了。不过,对于某些场景下向 SwiftUI 视图传递 managedObjectContext 环境变量(environment)总是会导致 Xcode 预览崩溃,这是怎么回事呢? 如上图所示,甚至我们将一个常驻内存…

VMware安装配置

1、官网下载VMware16 &#xff08;1&#xff09;进入VMware官网https://www.vmware.com/cn.html&#xff0c;之后点击下载里的Workstation Pro&#xff1a; &#xff08;2&#xff09;之后选择你要下载的VMware的版本&#xff0c;找到合适的下载&#xff0c;我这里以Windows系…

Python中的闭包和装饰器

一、闭包的定义与实例 1.1 闭包的定义与介绍 在Python实际开发过程中&#xff0c;调用函数过程中&#xff0c;函数内定义的变量都销毁了。此时由于业务需求可能需要保存函数内的这个变量&#xff0c;调用这个变量进行一系列操作。为了解决这个问题&#xff0c;引入闭包这个概念…

机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型

机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型 目录 机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型1 过拟合和欠拟合1.1 过拟合1.2 欠拟合 2 正则化惩罚2.1 概念2.2 函数2.3 正则化种类 3 K折交叉验证3.1 概念3.2 图片理解3.3 函数导入3.4 参数理解 4 训练模型K折交…

Qt 下位机串口模拟器

使用 vspd 创建虚拟配对串口&#xff0c;Qt 实现下位机串口模拟器&#xff0c;便于上位机开发及实时调试&#xff0c;适用字符串格式上下位机串口通信&#xff0c;数据包格式需增加自定义解析处理。 通过以下链接下载 vspd 安装包&#xff0c;进行 dll 破解。 链接: https://…

HarmonyNext 鸿蒙开发中,在H5 页面如何下载图片保存到媒体库。

作为一个资深的鸿蒙开发者,可以有偿解决你在开发过程中遇到的问题!!绿泡泡:781284440 1.首先安装 ohos-dsbridge 插件地址:OpenHarmony三方库中心仓 2. 在生命周期 aboutToApper 中注册全局方法 this.controller.addJavascriptObject(this, account); 3. 使用装饰器@Java…

Android 15 状态栏闹钟图标不显示问题修复

Android 15 状态栏闹钟图标不显示问题修复 问题描述 在 Android 15 系统中,发现即使设置了闹钟,状态栏也不会显示闹钟图标。这个问题影响了用户及时查看闹钟状态的体验。 问题分析 通过查看 SystemUI 的配置文件,发现在 frameworks/base/packages/SystemUI/res/values/conf…

vue 虚拟滚动 vue-virtual-scroller RecycleScroller

vue 3 https://github.com/Akryum/vue-virtual-scroller/blob/master/packages/vue-virtual-scroller/README.md vue 2 https://github.com/Akryum/vue-virtual-scroller/tree/v1/packages/vue-virtual-scroller npm install --save vue-virtual-scrollernextmain.js // 虚拟滚…

密钥登录服务器

1. 生成 SSH 密钥对 如果您还没有生成密钥对&#xff0c;可以使用以下命令生成&#xff1a; ssh-keygen 在 root 用户的家目录中生成了一个 .ssh 的隐藏目录&#xff0c;内含两个密钥文件&#xff1a;id_rsa 为私钥&#xff0c;id_rsa.pub 为公钥。 在提示时&#xff0c;您可…

30天开发操作系统 第 11 天 --制作窗口

前言 在harib07d中鼠标移动到右侧后就不能再往右移了,大家有没有觉得别扭?没错,在Windows 中&#xff0c;鼠标应该可以向右或向下移动到画面之外隐藏起来的&#xff0c;可是我们的操作系统却还不能实现这样的功能&#xff0c;这多少有些遗憾。 这是为什么呢?我们还是先来看一…

物理知识1——电流

说起电流&#xff0c;应该从电荷说起&#xff0c;而说起电荷&#xff0c;应该从原子说起。 1 原子及其结构 常见的物质是由分子构成的&#xff0c;而分子又是由原子构成的&#xff0c;有的分子是由多个原子构成&#xff0c;有的分子只由一个原子构成。而原子的构成如图1所示。…

Android性能分析工具的比较

背景介绍 Systrace、Perfetto和Android Benchmarking Framework都是用于性能分析和优化的工具&#xff0c;但它们各自的用途、功能范围和适用场景有所不同。以下对它们进行详细的比较。 通常一次较完整的性能分析过程需要多工具的配合使用&#xff0c;往复迭代&#xff1a; …

Jupyter在运行上出现错误:ModuleNotFoundError: No module named ‘wordcloud‘

问题分析&#xff1a;显示Jupyter未安装这个模板 解决办法&#xff1a;在单元格内输入&#xff1a;!pip install wordcloud

大模型WebUI:Gradio全解系列8——Additional Features:补充特性(下)

大模型WebUI&#xff1a;Gradio全解系列8——Additional Features&#xff1a;补充特性&#xff08;下&#xff09; 前言本篇摘要8. Additional Features&#xff1a;补充特性8.5 嵌入托管 Spaces8.5.1 使用 Web Components 嵌入1. 嵌入步骤2. 定义嵌入的外观和行为 8.5.2 使用…

持续学习入门

参考视频&#xff08;一&#xff09; 【学无止境&#xff1a;深度连续学习】 背景 更新新的数据时&#xff0c;数据异步输入&#xff0c;会有灾难性遗忘 现有解决策略 &#xff08;1&#xff09;引入正则约束&#xff08;2&#xff09;设计合适的动态模型架构 &#xff…