C++ inline 的更进一步理解
文章目录
- 1.概述
- 2.ODR(One Definition Rule)问题
- 3.范例测试代码
- 4.好坏分析
ODR: One Definition Rule,即单一定义规则, C++ 语言中非常重要的一项规则,它确保程序的行为一致性并避免链接时出现冲突。ODR 的核心思想是在整个程序中,每个实体(如变量、函数、类)应该有且仅有一个定义。
在一个程序的所有翻译单元(通常是源文件)中,同一个函数或变量只能有一个定义。如果某个函数或变量在多个翻译单元中有多个定义,那么编译器在链接阶段会报错。这是为了避免在程序中调用某个函数时,编译器不确定应该使用哪一个版本的定义。
inline: 在 C++ 中一般用于建议编译器将函数在调用处进行展开,从而减少函数调用的开销。它是一种编译器优化机制,通常用于小型、简单的函数。
1.概述
现代 C++ 中,inline 的一个重要作用是处理 One Definition Rule (ODR) 问题。
ODR 规定在一个程序中,每个非内联的实体(比如函数或变量)只能有一个定义。然而,如果我们在头文件中定义一个独立函数(而不是声明),并在多个源文件中包含这个头文件,那么编译过程中会产生多个相同的独立函数定义,从而在链接时引发错误。
2.ODR(One Definition Rule)问题
#ifndef _______
#define _______
#include <iostream>void print_message(){std::cout << "Hello,World" << std::endl;
}#endif
多个源码文件包含时:
chVYgFn.o:(.bss+0x0): first defined here
/usr/bin/ld: /tmp/ccMy1ZtX.o: in function `print_message()':
call.cpp:(.text+0x0): multiple definition of `print_message()'; /tmp/cchVYgFn.o:main.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
解决这个问题,C++11及之前,可以改为 static 函数
C++17及之后,可以如下修改:
#ifndef _______
#define _______
#include <iostream>inline void print_message(){std::cout << "Hello,World" << std::endl;
}#endif
这里 inline 的作用是告诉编译器和链接器:
- 这个独立函数或者变量可以在多个翻译单元中定义。
- 所有这些定义都应该被视为等效的同一个实体(允许多个TU中存在相同定义而不违背ODR,链接时按编译器实现链接某个实现)。
3.范例测试代码
header.h
#ifndef _______
#define _______
#include <iostream>// inline :C++ 17 可以使用 inline,允许多个TU中存在相同定义而不违背ODR,链接时按编译器实现链接某个实现
// static : 也可以使用 static// static/inline
int global_count = 0;// ODR ( One Definition Rule )
// inline 不光是展开,当头文件在多个头文件包含时,
// 没有inline就会存在多个相同函数,造成重定义。
// 但是添加inline,就会保持一份定义。并且与包含一份的 #ifndef / #define 无关。
// inline :C++ 17 可以使用 inline,允许多个TU中存在相同定义而不违背ODR,链接时按编译器实现链接某个实现
// static : 也可以使用 static// static/inline
void print_message(){std::cout << "Hello,World" << std::endl;
}#endif
call.cpp
#include "header.h"
main.cpp
#include "header.h"
#include "header.h"int main(){}
编译:
[root@VM-24-13-centos inline_ODR]# g++ main.cpp call.cpp
/usr/bin/ld: /tmp/ccMo6TBR.o:(.bss+0x0): multiple definition of `global_count'; /tmp/ccEKrehI.o:(.bss+0x0): first defined here
/usr/bin/ld: /tmp/ccMo6TBR.o: in function `print_message()':
call.cpp:(.text+0x0): multiple definition of `print_message()'; /tmp/ccEKrehI.o:main.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
[root@VM-24-13-centos inline_ODR]#
声明为 static 或 inline 或 static inline 便不再报错
#ifndef _______
#define _______
#include <iostream>static inline
int global_count = 0;static inline
void print_message(){std::cout << "Hello,World" << std::endl;
}#endif
现代C++更趋向于头文件包含实现,这样做就可以避免C++的ODR问题。
4.好坏分析
① static
- static 关键字用于将函数的链接类型设为内部链接。这意味着该函数的作用域仅限于定义它的翻译单元(通常是一个源文件)。
- 使用 static 修饰的函数在整个程序中是本地的,它不会在其他翻译单元中可见。因此,即使在不同的源文件中定义了同名的 static 函数,它们是互相独立的,不会引起冲突。
- static 本身并不会提示编译器进行函数展开。它只影响作用域和链接。
- 如果要 static 函数被展开,可以配合 inline 使用(static inline),这样既保证本地性又增加展开的可能性。
② inline
- inline 函数的链接类型为外部链接(如果没有其他修饰符影响)。它可以在多个翻译单元中使用,但这些翻译单元中的定义必须一致。
- 编译器会将所有使用 inline 关键字定义的同名函数视为同一个函数,并在链接阶段合并这些定义,从而避免 ODR(One Definition Rule) 问题。
- inline 是对编译器的建议,提示它可以在调用处直接展开函数体,从而减少函数调用的开销。但这不是强制的,最终是否展开由编译器决定。
- 在现代编译器中,即使没有 inline,编译器也能根据优化设置自动决定是否展开,因此 inline 更多是解决链接和 ODR 问题的工具。
③ 对比
static:本地可见,多份存在,互不冲突。
inline:被引用时,多份编译单元允许相同存在,解决 ODR 问题,并提示编译器可展开函数。
即,期望应用如下:
- 头文件中定义一个函数并希望它能被多个翻译单元使用,又不想发生链接冲突,就用 inline (C++17起)
- 期望一个函数只在当前翻译单元内可见并且避免与其他文件的同名函数冲突,就用 static
相关文章:
C++ inline 的更进一步理解
文章目录 1.概述2.ODR(One Definition Rule)问题3.范例测试代码4.好坏分析 ODR: One Definition Rule,即单一定义规则, C 语言中非常重要的一项规则,它确保程序的行为一致性并避免链接时出现冲突。ODR 的核心思想是在整个程序中,每…...
海康威视云台相机图像获取
直接上代码: import cv2# 替换为正确的RTSP链接 rtsp_url rtsp://admin:abcd12345192.168.1.64:554/h264/ch1/main/av_stream cap cv2.VideoCapture(rtsp_url)if not cap.isOpened():print("无法打开视频流,检查RTSP URL和凭证") else:whil…...
什么是词嵌入(Word Embedding)
1. 什么是词嵌入(Word Embedding) ⾃然语⾔是⼀套⽤来表达含义的复杂系统。在这套系统中,词是表义的基本单元。顾名思义,词向量是⽤来表⽰词的向量,也可被认为是词的特征向量或表征。把词映射为实数域向量的技术也叫词嵌⼊(word e…...
LSTM时间序列模型实战——预测上证指数走势
LSTM时间序列模型实战——预测上证指数走势 关于作者 作者:小白熊 作者简介:精通python、matlab、c#语言,擅长机器学习,深度学习,机器视觉,目标检测,图像分类,姿态识别,…...
基于 STM32F407 的 SPI Flash下载算法
目录 一、概述二、自制 FLM 文件1、修改使用的芯片2、修改输出算法的名称3、其它设置4、修改配置文件 FlashDev.c5、文件 FlashPrg.c 的实现 三、验证算法 一、概述 本文将介绍如何使用 MDK 创建 STM32F407 的 SPI Flash 下载算法。 其中,SPI Flash 芯片使用的是 W…...
力扣之1355.活动参与者
题目: Sql 测试用例: Create table If Not Exists Friends (id int, name varchar(30), activity varchar(30)); Create table If Not Exists Activities (id int, name varchar(30)); Truncate table Friends; insert into Friends (id, name, acti…...
数据资产治理:构建敏捷与安全的数据管理体系
在当今数字化的盛况下,作为核心资产的数据已经越发受到企业的重视。但是随着公司的逐步壮大,如何分析这些数据以及如何有效治理数据资产,以确保安全性、合规性以及易用性,是企业面临的重大挑战。数聚股份将从多年从业经验深度探讨…...
Nodejs连接Mysql笔记
框架搭建 安装Node.js 首先,确保你已经在系统上安装了Node.js和npm(Node Packaged Modules)。你可以通过以下命令检查是否已经安装:shell 或者 node -v 或者 npm -v 数据库连接代码 1.导入MySQL2库 npm install mysql2 2.在文件…...
Canvas:AI协作的新维度
在人工智能的浪潮中,OpenAI的最新力作Canvas,不仅是一款新工具,它标志着人工智能协作方式的一次革命性飞跃。Canvas为写作和编程提供了一个全新的交互界面,让用户能够与ChatGPT进行更紧密、更直观的协作。 Canvas的…...
【深度学习】— softmax回归、网络架构、softmax 运算、小批量样本的向量化、交叉熵
【深度学习】— softmax回归、网络架构、softmax 运算、小批量样本的向量化、交叉熵 3.4 Softmax 回归3.4.1 分类问题3.4.2 网络架构 3.4.3 全连接层的参数开销3.4.4 softmax 运算3.4.5 小批量样本的向量化3.4.6 损失函数对数似然softmax 的导数 3.4.7 信息论基础熵信息量重新审…...
C# Wpf 图片按照鼠标中心缩放和平移
C# Wpf 图片按照鼠标中心缩放和平移 1、缩放事件 MouseWheel(object sender, MouseWheelEventArgs e)2、平移相关的事件 MouseMove(object sender, MouseEventArgs e) MouseDown(object sender, MouseButtonEventArgs e) MouseUp(object sender, MouseButtonEventArgs e)3、…...
网络安全产品类型
1. 防火墙(Firewall) 功能:防火墙是网络安全的第一道防线,通过检查进出网络的流量来阻止未经授权的访问。它可以基于预定义的安全规则,过滤数据包和阻止恶意通信。 类型: 硬件防火墙:以专用设备…...
【开源风云】从若依系列脚手架汲取编程之道(五)
📕开源风云系列 🍊本系列将从开源名将若依出发,探究优质开源项目脚手架汲取编程之道。 🍉从不分离版本开写到前后端分离版,再到微服务版本,乃至其中好玩的一系列增强Plus操作。 🍈希望你具备如下…...
金融市场的衍生品交易及其风险管理探讨
金融衍生品市场是现代金融体系的重要组成部分,其交易量和复杂性在过去几十年中迅速增长。衍生品,如期权、期货、掉期等,因其灵活性和杠杆效应,广泛应用于风险管理、投机和资产配置等多个领域。本文将探讨金融衍生品交易的关键特点…...
一、创建型(单例模式)
单例模式 概念 单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。它控制类的实例化过程,防止外部代码创建新的实例。 应用场景 日志记录:确保只有一个日志记录器,以便于管理和避免重复记…...
毕业设计项目-古典舞在线交流平台的设计与实现(源码/论文)
项目简介 基于springboot实现的,主要功能如下: 技术栈 后端框框:springboot/mybatis 前端框架:html/JavaScript/Css/vue/elementui 运行环境:JDK1.8/MySQL5.7/idea(可选)/Maven3(…...
【秋招笔试】10.09华子秋招(已改编)-三语言题解
🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 大厂实习经历 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 本次的三题全部上线…...
【算法笔记】双指针算法深度剖析
【算法笔记】双指针算法深度剖析 🔥个人主页:大白的编程日记 🔥专栏:算法笔记 文章目录 【算法笔记】双指针算法深度剖析前言一.移动零1.1题目1.2思路分析1.3代码实现 二.复写零2.1题目2.2思路分析2.3代码实现 三.快乐数3.1题目…...
第二十二天|回溯算法| 理论基础,77. 组合(剪枝),216. 组合总和III,17. 电话号码的字母组合
目录 回溯算法理论基础 1.题目分类 2.理论基础 3.回溯法模板 补充一个JAVA基础知识 什么时候用ArrayList什么时候用LinkedList 77. 组合 未剪枝优化 剪枝优化 216. 组合总和III 17. 电话号码的字母组合 回溯法的一个重点理解:细细理解这句话!…...
关闭IDM自动更新
关闭IDM自动更新 1 打开注册表2 找到IDM注册表路径 1 打开注册表 winR regedit 2 找到IDM注册表路径 计算机\HKEY_CURRENT_USER\Software\DownloadManager 双击LstCheck,把数值数据改为0 完成 感谢阅读...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
