C/C++ 中的未定义行为(Undefined Behavior, UB)
0. 简介
在 C/C++ 编程中,理解未定义行为(UB)及其相关概念至关重要。本文将对未定义行为进行详细解析,并通过实例展示其影响与处理方法。
1. 概念辨析
在 C/C++ 中,未定义行为容易与以下两个概念混淆:
1.1 实现定义行为
实现定义行为是指程序的行为依赖于具体的实现,而标准要求实现必须为每种行为提供文档说明。例如,int 类型在不同环境下的大小可能不同,标准要求至少为 16 位,而大多数环境下为 32 位。
1.2 未指明行为
未指明行为也是依赖于具体实现,但标准并不要求提供文档说明。虽然行为可能变化,但其结果应是合法的。比如,变量的分配方式和位置可以是连续的,也可以是分开的。
1.3 未定义行为
未定义行为则是对程序行为没有任何限制,标准不要求程序产生任何合法或有意义的结果。例如,访问非法内存就是未定义行为。
当然可以,下面是对之前代码的修改和未定义行为检测方法的详细说明。
2. 为什么会有未定义行为?
C/C++ 的设计目标之一是高效,因此未定义行为的存在使得编译器能够优化程序。检测未定义行为的难度较大,例如,带符号整数溢出并不总是会在编译阶段显现出来。若编译器必须处理这些未定义行为,可能会影响程序的优化能力。
因此,将某些操作定义为未定义行为,编译器可以在优化时忽略这些情况,从而生成更高效的代码。这也是为何在开启优化选项后,程序可能会表现出意料之外的行为。

3. 未定义行为的例子
3.1 带符号整数算术溢出
#include <iostream>
using namespace std;int main() {int x;cout << "请输入一个整数: ";cin >> x;// 检查溢出if (x > 0 && x + 1 < x) {cout << "Overflow!" << endl;} else {cout << "Not overflow!" << endl;}return 0;
}
在开启优化选项时,可能会发现预期的 “Overflow!” 并未出现。原因在于带符号整数溢出被视为未定义行为,编译器因此可能忽略了该情况。
3.2 越界访问
#include <iostream>
using namespace std;int main() {int arr[5] = {0, 1, 2, 3, 4};int index;cout << "请输入数组索引(0-4之间的数字): ";cin >> index;// 检查越界if (index >= 0 && index < 5) {cout << "数组中的值: " << arr[index] << endl;} else {cout << "索引越界!" << endl;}return 0;
}
C/C++ 并不自动进行数组越界检查,导致可能出现以下后果:
- 访问非法内存引发运行时错误(RE)
- 意外修改其他变量的值
不进行越界检查的原因在于其成本较高,并可能影响程序的优化机会。
3.3 无可视副作用的无限循环
#include <iostream>
using namespace std;bool checkCondition() {unsigned cnt = 0;while (true) {if (cnt < 0) return true; // 这个条件永远不会为真}return false;
}int main() {if (checkCondition()) {cout << "This program has been terminated." << endl;} else {cout << "Some strange things happened!" << endl;}return 0;
}
由于 checkCondition() 函数中的无限循环为未定义行为,编译器可能会将其优化掉,从而导致不同的行为表现。
3.4 无法确定的运算顺序
#include <iostream>
using namespace std;int main() {int x = 1;int result = (x++ + ++x); // 无法确定的运算顺序cout << "结果: " << result << endl;return 0;
}
在此例中,x++ 和 ++x 的副作用无顺序,因此结果是未定义的。
3.5 访问未初始化变量
#include <iostream>
using namespace std;int main() {int x; // 未初始化cout << "未初始化变量的值: " << x << endl; // 结果未定义return 0;
}
访问未初始化的变量同样是未定义行为,可能导致不确定的输出。
4. 如何检测未定义行为?
虽然编译期检测未定义行为较为困难,但运行时可以通过一些工具来捕捉。以下是一些常用的方法:
4.1 使用 -fsanitize=undefined
在使用 Clang 或 GCC 编译器时,可以添加 -fsanitize=undefined 选项来启用未定义行为检测。例如:
g++ -fsanitize=undefined -o my_program my_program.cpp
这将帮助你在运行时捕获未定义行为。如果想要将编译器切换成更严格的clang,则可以按照下面的操作:CLion设置Clang为默认编译器 (Ubuntu平台)
4.2 使用 Valgrind
Valgrind 是一个强大的内存调试工具,可以帮助检测内存错误,包括未定义行为。可以通过以下命令运行程序:
valgrind ./my_program
Valgrind 将报告内存访问错误、未初始化变量的使用等问题。
4.3 使用 AddressSanitizer
AddressSanitizer 也是一个运行时检测工具,专门用于检测内存错误和未定义行为。可以通过以下方式编译:
g++ -fsanitize=address -o my_program my_program.cpp
然后运行程序,AddressSanitizer 会报告内存错误。
4.3.1 在 CLion 下使用
在 CLion 中,集成了对 Google Sanitizers 的支持,使得开发人员能够有效地检测和调试代码中的内存问题。通过简单的配置,你可以在项目中启用 AddressSanitizer(ASan)等工具,以帮助识别内存泄漏和其他相关问题。要在 CLion 中使用 ASan,首先需要在 CMakeLists.txt 文件中添加一个开关。以下是一个示例配置:
cmake_minimum_required(VERSION 3.21)
project(mem_leak_test)
set(CMAKE_CXX_STANDARD 14)if (ENABLE_ASAN)message(STATUS "build with ASAN")set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
endif ()add_executable(mem_leak_test main.cpp)
在这段代码中,我们定义了一个名为 ENABLE_ASAN 的选项,若该选项被启用,编译器将会添加 -fsanitize=address 编译标志,这样就可以启用 AddressSanitizer。在 CLion 中配置 CMake 时,可以通过以下步骤传入 ENABLE_ASAN

同理,如果你在 macOS 上使用 llvm clang++,也可以在配置中指定 compiler 的路径:

设置完毕后,之间运行代码,如果出现内存问题,CLion 会在 Sanitizers 窗口中提示信息:

4.4 使用 Clang Static Analyzer
…详情请参照古月居
相关文章:
C/C++ 中的未定义行为(Undefined Behavior, UB)
0. 简介 在 C/C 编程中,理解未定义行为(UB)及其相关概念至关重要。本文将对未定义行为进行详细解析,并通过实例展示其影响与处理方法。 1. 概念辨析 在 C/C 中,未定义行为容易与以下两个概念混淆: 1.1 …...
AJAX 1——axios体验、认识URL、常用请求方法、HTTP协议、错误处理、form-serialize插件
AJAX 1——axios体验、认识URL、常用请求方法、HTTP协议、错误处理、form-serialize插件 1.AJAX入门与体验axios 定义:浏览器与服务器进行数据通信的技术 体验axios库,与服务器通信 引入axios.js使用axios函数 <p class"my-p"></p&…...
Java-运算符
一、运算符是什么? 其实就如字面意思一样啦~就像数学中的运算符一样:(" "," - "," * "," / "," % "...)。 计算机的用途就如其名:运算。而既然要运算…...
ubutun nginx 安装和解决端口占用问题
目录 一、删除已有nginx 二、安装nginx 三、端口占用问题 分析问题 解决方法:更换默认端口 nginx是一个高性能的 HTTP 和反向代理 web 服务器,同时也提供了 IMAP/POP3/SMTP 服务。是一款轻量级的 Web 服务器/反向代理服务器及电子邮件(I…...
螺蛳壳里做道场:老破机搭建的私人数据中心---Centos下Docker学习01(环境准备)
1 准备工作 由于创建数据中心需要安装很多服务器,这些服务器要耗费很所物理物理计算资源、存储资源、网络资源和软件资源,作为穷学生只有几百块的n手笔记本,不可能买十几台服务器来搭建数据中心,也不愿意跑实验室,想躺…...
解决:使用layui.treeTable.updateNode,更新表格数据后,done里面的事件丢失问题
1. 背景 在给树形表格添加行点击事件,并且只更新当前行数据。 treeTable.updateNode("SpeProjListId", result.LAY_DATA_INDEX, result);更新数据后,点击事件失效。 1. 给字段绑定事件: class"link_a link_style" , {…...
【Linux】环境变量(初步认识环境变量)
文章目录 1. 环境变量1.1 基本概念 2. 认识常见环境变量2.1 PATH2.2 HOME2.3 SHELL2.4 PWD2.5 USER 3. 理解环境变量 1. 环境变量 在main函数的命令行参数中,有argc、argv、env三个参数。 argc:命令行参数的个数argc:存放每个参数的具体数值…...
79. 单词搜索
思路 每次以当前位置为初始位置开始遍历,看是否找到单词 (以官方题解做出) v:代表等于work[k]且已走过的位置 d:四个方向 回溯(遍历): 匹配不上:终止 找到了:终止(先…...
[单master节点k8s部署]28.Istio流量管理(四)
金丝雀发布实验 部署两个pod,他们分别是canary-v1和canary-v2。 随后进行service的部署: apiVersion: v1 kind: Service metadata:name: canary-svc34namespace: default spec:selector:apply: canaryports:- port: 80protocol: TCPtargetPort: 80进行…...
Windows 11 安装配置 Git 教程
目录 Git Windows 11 环境安装配置 Git Git Git是一个开源的分布式版本控制系统,由Linus Torvalds创建,用于有效、高速地处理从小到大的项目版本管理。Git是目前世界上最流行的版本控制系统,广泛应用于软件开发中。 以下是Git的一些关键特…...
Go基础学习11-测试工具gomock和monkey的使用
文章目录 基础回顾MockMock是什么安装gomockMock使用1. 创建user.go源文件2. 使用mockgen生成对应的Mock文件3. 使用mockgen命令生成后在对应包mock下可以查看生成的mock文件4. 编写测试代码5. 运行代码并查看输出 GomonkeyGomonkey优势安装使用对函数进行monkey对结构体中方法…...
PHP基础教程
PHP基础教程 1. PHP简介 PHP是一种广泛使用的开源服务器端脚本语言,它特别适用于网页开发,并可嵌入到HTML中使用。 2. PHP环境搭建 Windows: 可以使用XAMPP或WAMP。Mac: 可以使用MAMP。Linux: 可以使用XAMPP或LAMP。 3. 第一个PHP程序 创建一个名为…...
Python或R时偏移算法实现
🎯要点 计算单变量或多变量时序距离,使用欧几里得、曼哈顿等函数量化不同时序差异。量化生成时序之间接近度相似性矩阵。使用高尔距离和堪培拉距离等相似度测量。实现最小方差匹配算法,绘制步进模式的图形表示。其他语言包算法实现。 &…...
华为云LTS日志上报至观测云最佳实践
华为云LTS简介 华为云云日志服务(Log Tank Service,简称 LTS),用于收集来自主机和云服务的日志数据,通过海量日志数据的分析与处理,可以将云服务和应用程序的可用性和性能最大化,为您提供实时、…...
Python--加载Hugging Face模型文件异常处理
尝试加载 Hugging Face 模型的配置文件时,无法从 https://huggingface.co 获取所需的 config.json 文件。这个错误通常是由于网络连接问题、访问受限或路径配置错误导致的。让我们一步步分析并解决这个问题。 可能原因及解决方案: 网络连接问题…...
补码加/减运算的具体示例
补码加法运算示例 示例:计算两个十进制数的和,35 18,假设使用8位二进制表示。 1、求原码: 35的原码:00100011 18的原码:00010010 2、求补码(对于正数,补码与原码相同࿰…...
macOS编译和运行prometheus2.54
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文详述了在macOS(M2芯片)上编译和运行prometheus2.54版本的过程,以及安装node_exporter和grafana并使用prometheus指标进行展示 本地…...
flume系列之:flume jmx页面导出flume、java进程等全部指标
flume系列之:flume jmx页面导出flume、java进程等全部指标 一、需求背景二、完整的jmx指标信息三、修改jmx指标导出规则四、启动jmx导出程序一、需求背景 目前jmx页面指标只导出了flume相关的指标,现在需要导出java相关的指标二、完整的jmx指标信息 主要有flume指标java进程指…...
(17)MATLAB使用伽马(gamma)分布生成Nakagami-m分布的方法1
文章目录 前言一、使用伽马分布生成Nakagami分布随机变量的方法一二、MATLAB仿真代码后续 前言 MATLAB在R2013a版本中引入Nakagami分布对象,可以用来生成Nakagami随机变量。但是在更早的MATLAB版本中,并没有可以直接生成 Nakagami分布的随机变量的内置的…...
NFT 是什么?
NFT 是什么? NFT,全称Non-Fungible Token,即“非同质化代币”,是一种基于区块链技术的独特数字资产。NFT的核心特性在于其唯一性、不可分割性和不可替代性,这使其与传统的加密货币(如比特币、以太坊等)形成了鲜明的对比。比特币等加密货币是同质化的,每个单位之间可以…...
Phi-4-mini-reasoning与IDEA集成开发:提升Java代码推理与注释生成效率
Phi-4-mini-reasoning与IDEA集成开发:提升Java代码推理与注释生成效率 1. 引言:当AI遇见Java开发 作为一名Java开发者,你是否经常遇到这样的困扰:接手一个复杂项目时,面对层层嵌套的代码逻辑感到无从下手;…...
小型物联网系统——家居网关设计(C语言实现)
一、系统概述 家居网关是小型物联网系统的核心枢纽,负责多协议设备接入、数据汇聚转发、本地/远程控制三大核心功能。本设计基于STM32F103C8T6主控,集成Zigbee(传感器接入)、Wi-Fi(云端通信)、GPIO…...
基于YOLOv8深度学习的花卉识别检测系统(YOLOv8+YOLO数据集+UI界面+Python项目源码+模型)
一、项目介绍 随着计算机视觉技术的快速发展,基于深度学习的图像识别技术在植物分类与识别领域展现出巨大的应用潜力。本系统基于先进的YOLOv8目标检测算法,构建了一个高效准确的花卉识别检测系统,能够实现对13种不同花卉的实时检测与识别。…...
FPGA实战:手把手教你用Verilog实现以太网PHY芯片MDIO寄存器读写(附完整代码)
FPGA实战:手把手教你用Verilog实现以太网PHY芯片MDIO寄存器读写 在当今高速网络设备开发中,FPGA与以太网PHY芯片的协同工作已成为工业级设计的标配。MDIO(Management Data Input/Output)接口作为IEEE 802.3标准定义的两线制串行总…...
从检测到分析:手机位置热力图生成与行为模式挖掘扩展方案
从检测到分析:手机位置热力图生成与行为模式挖掘扩展方案 1. 引言:从“看见”到“看懂” 想象一下,你在一间大型会议室里,墙上挂着十几个监控摄像头。传统的监控系统能告诉你“画面里有手机”,但仅此而已。你无法知道…...
无人机飞控入门:如何理解Pixhawk/PX4里的那个“六自由度模型”?
无人机飞控入门:从代码视角理解PX4的六自由度模型 当你第一次打开PX4的EKF2(扩展卡尔曼滤波)模块代码时,那些关于body_frame、earth_frame和angular_rates的变量命名是否让你感到困惑?这些看似抽象的术语背后ÿ…...
【优选算法篇】拓扑排序——逻辑先后与任务依赖的终极拆解
文章目录逻辑的枷锁:在依赖网中寻找出路零、 拓扑排序:打破逻辑混乱的“秩序之光”一、 课程表 I & II:经典拓扑排序 (Medium)1.1 题目描述1.2 算法思路:依赖关系的剥离1.3 C 代码实战 (以课程表 II 为例)二、 火星词典&#…...
音乐标签编辑器:让本地音乐元数据管理效率提升90%的开源工具
音乐标签编辑器:让本地音乐元数据管理效率提升90%的开源工具 【免费下载链接】music-tag-web 音乐标签编辑器,可编辑本地音乐文件的元数据(Editable local music file metadata.) 项目地址: https://gitcode.com/gh_mirrors/mu/…...
如何让Windows 11告别臃肿?Win11Debloat完整指南帮你一键优化系统
如何让Windows 11告别臃肿?Win11Debloat完整指南帮你一键优化系统 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to declu…...
前后端时间数据类型不一致如何解决
本文分析了前端和后端时间数据类型的不一致性,并提供了具体的解决方案。问题的根源是后端返回的时间数据类型与前端预期类型不一致,导致前端无法直接处理。后端采用Javatimestamp类型和MySQLdatetime类型存储时间,前端typescript定义createti…...
