C++初学者指南-4.诊断---基础:警告和测试
C++初学者指南-4.诊断—基础知识:警告和测试
文章目录
- C++初学者指南-4.诊断---基础知识:警告和测试
- 1. 术语和技术
- 记住:使用专用类型!
- 2.编译器警告
- Gcc/CLang 编译器选项
- MS Visual Studio 编译器选项
- 3.断言
- 运行时断言
- 静态断言(C++11)
- 4.测试
- 指南
- doctest 简单测试案例
- doctest 子用例
- 不要直接使用 cin/cout/cerr!
1. 术语和技术
Warnings 警告 | 编译器消息提示潜在的运行时行为问题的陷阱 | (见下文) |
Assertions 断言 | 用于比较和报告表达式的预期值和实际值的语句 | (见下文) |
Testing 测试 | 比较程序部分或整体的实际行为和预期行为 | (见下文) |
Code Coverage 代码覆盖率 | 实际执行或测试的代码量 | gcov… |
Static Analysis 静态分析 | 通过分析源代码,发现潜在的运行时问题,比如未定义的行为 | ASAN UBSAN… |
Dynamic Analysis 动态分析 | 通过运行实际程序来发现潜在问题,比如内存泄漏 | valgrind… |
Debugging 调试 | 在运行时单步执行代码并检查内存中值 | (接下来) |
Profiling 分析 | 找出每个函数/循环/代码块对总运行时间、内存消耗的影响有多大 | |
Micro Benchmarking 微基准测试 | 衡量单个函数或一组语句/调用运行时间的小测试,而不是整个程序运行 |
记住:使用专用类型!
- 限制输入参数值
- 确保中间结果的有效性
- 保证返回值的有效性
目标:编译器作为正确性检查工具-如果编译成功,那就应该是正确的。
// 输入保证:角度以弧度为单位
Square make_rotated (Square const&, Radians angle);
// 输入保证:仅有效数量(例如 > 0)
Gadget duplicate (Gadget const& original, Quantity times);
// 结果保证:向量已经归一化
UnitVector3d dominant_direction (WindField const&);
// 避免混淆,使用一个好的单位库
si::kg mass (EllipsoidShell const&, si::g_cm3 density);
…
2.编译器警告
编译器错误 = 程序不可编译
编译器警告 = 程序可编译,但有一段有问题的代码可能会导致运行时错误
Gcc/CLang 编译器选项
重要
-Wall | 强烈推荐。你应该始终至少使用这个。它并不完全启用所有警告,而是启用那些最重要的,不会产生太多误报的警告。 |
-Wextra | 启用比 -Wall 还多的警告。强烈推荐 |
-Wpedantic | 强烈推荐。需按照严格的ISO C++发出所有警告,拒绝编译器特定的扩展 |
-Wshadow | 强烈建议。当变量或类型声明相互遮蔽时发出警告 |
-Werror | 将所有警告视为错误⇒任何警告都将终止编译 |
-fsanitize=undefined,address | 启用未定义行为检测器和地址检测器(后文将更详细介绍) |
推荐的编译选项(生产级别)
-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Werror -fsanitize=undefined,address -Wfloat-equal -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wformat=2 -Wimport -Winvalid-pch -Wlogical-op -Wmissing-declarations -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wnested-externs -Wpacked -Wpointer-arith -Wredundant-decls -Wstack-protector -Wstrict-null-sentinel -Wswitch-enum -Wundef -Wwrite-strings
高性能/低内存/安全
注:这里的吵和噪音是指有很多警告的意思
可能会很吵!
-Wdisabled-optimization -Wpadded -Wsign-conversion -Wsign-promo -Wstrict-aliasing=2 -Wstrict-overflow=5 -Wunused -Wunused-parameter
MS Visual Studio 编译器选项
/W1 | 1 级:严重警告 |
/W2 | 2 级:重大警告 |
/W3 | 3 级:生产级别警告。 您应该始终至少使用这个。 也是较新的 Visual Studio 项目的默认值。 |
/W4 | 强烈推荐,特别是对于新项目。 并没有真正启用所有警告,而是启用最多的警告 重要的不会产生太多误报噪音。 |
/Wall | 启用比 4 级更多的警告;可能有点太吵了 |
/WX | 将所有警告视为错误⇒任何警告都会终止编译 |
3.断言
运行时断言
#include <cassert>
assert(bool_expression);
如果表达式 产生 false,则中止程序
用例:
- 在运行时检查预期值/条件
- 验证先决条件(输入值)
- 验证不变量(例如,中间状态/结果)
- 验证后置条件(输出/返回值)
应在发布版本中停用运行时断言 以避免任何性能影响。
#include <cassert>
double sqrt (double x) {assert( x >= 0 );…
}
double r = sqrt(-2.3);
$ g++ … -o runtest test.cpp
$ ./runtest
runtest: test.cpp:3: void sqrt(double): Assertion `x >= 0' failed.
Aborted
逗号必须用括号保护
assert 是一个预处理器宏(稍后会详细介绍) 否则逗号将被解释为宏参数分隔符:
assert( min(1,2) == 1 ); // ERROR
assert((min(1,2) == 1)); // OK
断言信息
可以使用自定义宏添加(没有标准方法):
#define assertmsg(expr, msg) assert(((void)msg, expr))
assertmsg(1+2==2, "1 plus 1 must be 2");
(不)激活 – g++/clang
通过定义预处理器宏 NDEBUG 来停用断言, 例如,使用编译器开关:
g++ -DNDEBUG …
(不)激活 – MS Visual Studio
断言已被明确激活
- 如果预处理宏 _DEBUG 被定义,例如,通过编译器开关 /D_DEBUG
- 如果提供了编译器开关/MDd
如果在项目设置中或使用编译器开关/DNDEBUG定义了预处理宏NDEBUG,那么断言会被明确地禁用。
静态断言(C++11)
static_assert(bool_constexpr, "message");
static_assert(bool_constexpr); (C++17)
如果编译时常量表达式产生 false,则中止编译。
…
using index_t = int;
index_t constexpr DIMS = 1; // oops
void foo () { static_assert(DIMS > 1, "DIMS must be at least 2");…
}
index_t bar (…) {static_assert(std::numeric_limits<index_t>::is_integer &&std::numeric_limits<index_t>::is_signed, "index type must be a signed integer");…
}
$ g++ … test.cpp
test.cpp: In function 'void foo()':
test.cpp:87:19: error: static assertion failed: DIMS must be at least 287 | static_assert(DIMS > 1, "DIMS must be at least 2");| ~~^~~
4.测试
指南
使用断言
检查类型无法表达或保证的期望和假设:
- 仅在运行时可用的期望值
- 前提条件(输入值)
- 不变量(例如,中间状态/结果)
- 后置条件(输出/返回值)
在发布版本中应该关闭运行时断言,以避免任何性能影响。
编写测试
一旦确定了函数或类型的基本用途和接口。
- 更快的开发:减少耗时的日志记录和调试会话需求。
- 更容易的性能调优:可以持续检查是否仍然正确。
- 文档:期望/假设被写在代码中。
使用测试框架
更方便,更少出错:预定义检查、设置设施、测试运行器等。
初学者 / 较小的项目: doctest
- 非常简洁和自我说明的风格
- 轻松设置:只需包含一个标题
- 非常快的编译
大型项目:Catch2
- 与doctest相同的基本理念(doctest是模仿Catch设计的)。
- 用不同数值执行相同测试的数值生成器。
- 使用计时器进行微基准测试,取平均值等。
- 编译速度较慢,设置起来比doctest稍微复杂一些。
doctest 简单测试案例
// 摘自文档测试教程:
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
int factorial (int n) {if (n <= 1) return n;return factorial(n-1) * n;
}
TEST_CASE("testing factorial") {CHECK(factorial(0) == 1);CHECK(factorial(1) == 1);CHECK(factorial(2) == 2);CHECK(factorial(3) == 6);CHECK(factorial(10) == 3628800);
}
$ g++ … -o runtest test.cpp
$ ./runtest
test.cpp(7) FAILED!
CHECK( factorial(0) == 1 )
with expansion:
CHECK( 0 == 1 )
测试失败,因为factorial的实现无法正确处理 n = 0 的情况。
运行此示例
doctest 子用例
// 摘自文档测试教程:
TEST_CASE("vectors can be sized and resized") {std::vector<int> v(5);REQUIRE(v.size() == 5);REQUIRE(v.capacity() >= 5);SUBCASE("push_back increases the size") {v.push_back(1);CHECK(v.size() == 6);CHECK(v.capacity() >= 6);}SUBCASE("reserve increases the capacity") {v.reserve(6);CHECK(v.size() == 5);CHECK(v.capacity() >= 6);}
}
对于每个子用例,测试用例都是从头开始执行的。
当执行每个子用例时,我们知道vector大小为 5,容量至少为 5。 我们在顶层通过 REQUIRE 强制执行这些要求。
- 如果 CHECK 失败:测试被标记为失败,但执行会继续进行。
- 如果 REQUIRE 失败:执行停止。
运行此示例
不要直接使用 cin/cout/cerr!
直接使用全局 I/O 流使得函数或类型难以测试:
void bad_log (State const& s) { std::cout << … }
在函数中:通过引用传递流
struct State { std::string msg; … };void log (std::ostream& os, State const& s) { os << s.msg; }TEST_CASE("State Log") {State s {"expected"};std::ostringstream oss;log(oss, s);CHECK(oss.str() == "expected");
}
运行上面示例
类范围:存储流指针
但是:请尝试编写与流或任何其他特定I/O方法无关的类型。
class Logger {std::ostream* os_;int count_;
public:explicitLogger (std::ostream* os): os_{os}, count_{0} {}…bool add (std::string_view msg) {if (!os_) return false;*os_ << count_ <<": "<< msg << '\n';++count_;return true;}
};TEST_CASE("Logging") {std::ostringstream oss;Logger log {&oss};log.add("message");CHECK(oss.str() == "0: message\n");
}
运行上面示例
附上原文链接
如果文章对您有用,请随手点个赞,谢谢!^_^
相关文章:

C++初学者指南-4.诊断---基础:警告和测试
C初学者指南-4.诊断—基础知识:警告和测试 文章目录 C初学者指南-4.诊断---基础知识:警告和测试1. 术语和技术记住:使用专用类型! 2.编译器警告Gcc/CLang 编译器选项MS Visual Studio 编译器选项 3.断言运行时断言静态断言&#x…...

docker使用镜像jms_all部署jumpserver
创建容器需要挂载出来的服务器对应目录 mkdir -p /data/redis/data mkdir -p /opt/mysql/{data,conf,logs}docker安装redis docker run -d -it --name redis -p 6379:6379 -v /data/redis/data:/data --restart=always...

在Java项目中集成单元测试与覆盖率工具
在Java项目中集成单元测试与覆盖率工具 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 单元测试是软件开发中至关重要的一环,它用于验证代码在独立…...

CTF实战:从入门到提升
CTF实战:从入门到提升 🚀前言 没有网络安全就没有国家安全,网络安全不仅关系到国家整体信息安全,也关系到民生安全。近年来,随着全国各行各业信息化的发展,网络与信息安全得到了进一步重视,越…...

Spring Boot集成olingo快速入门demo
1.什么是olingo? Apache Olingo 是个 Java 库,用来实现 Open Data Protocol (OData)。 Apache Olingo 包括服务客户端和 OData 服务器方面。 Open Data Protocol (开放数据协议,OData) 是用来查询和更新数据的一种W…...

GPT对话代码库——HAL库下 USART 的配置及问题(STM32G431CBT6)
目录 1,问: 1,答: 示例代码 正确的HAL库初始化方式 自定义初始化方式(不推荐) 总结 2,问: 2,答: 代码详细解释 初始部分 主初始化部分 初始化调用…...

ExoPlayer架构详解与源码分析(14)——ProgressiveMediaPeriod
系列文章目录 ExoPlayer架构详解与源码分析(1)——前言 ExoPlayer架构详解与源码分析(2)——Player ExoPlayer架构详解与源码分析(3)——Timeline ExoPlayer架构详解与源码分析(4)—…...

docker部署kafka(单节点) + Springboot集成kafka
环境: 操作系统:win10 Docker:Docker Desktop 4.21.1 (114176)、Docker Engine v24.0.2 SpringBoot:2.7.15 步骤1:创建网络: docker network create --subnet172.18.0.0/16 net-kafka 步骤2:安…...

一.1.(3)半导体二极管基本电路的分析方法及常见应用电路
1.二极管基本电路的分析方法 先标正负极,再看是否理想二极管 将二极管视为断路,求两端电压 两端电压均大于导通电压,压差大的先导通(由于电源不是完全的阶跃,而是有一个电压爬升的过程) 2.常见应用电路 1.求…...

银河麒麟V10 SP1 审计工具 auditd更新
前言 银河麒麟V10 SP1 审计工具 auditd 引发的内存占用过高, 内存使用率一直在 60% 以上, 内存一直不释放 排查 可以使用ps或者top查看系统进程使用情况 ps -aux|sort -k4nr|head -n 5 发现银河麒麟审计工具 auditd 一直占用内存不释放 解决 办法一…...

JWT(Json Web Token)在.NET Core中的使用
登录成功时生成JWT字符串目录 JWT是什么? JWT的优点: JWT在.NET Core 中的使用 JWT是什么? JWT把登录信息(也称作令牌)保存在客户端为了防止客户端的数据造假,保存在客户端的令牌经过了签名处理…...

《QT从基础到进阶·四十三》QPlugin插件多线程问题和只有插件dll没有头文件和lib文件时调用插件中的方法
1、插件和多线程问题: 创建插件对象不能放到多线程执行,不然报错:ASSERT failure in QWidget: "Widgets must be created in the GUlthread. //不能放在多线程执行 QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName))…...

Android SurfaceFlinger——屏幕状态初始化(二十二)
对于开机启动动画前期准备的相关步骤,我们已经分析了前 5 个,对于第 6 步调用 eglGetDisplay() 函数对 OpenGL ES 初始化并获取默认屏幕,我们在介绍 OpenGL ES 的时候也进行了详细的分析,下一步我们我们来分析对屏幕的状态进行初始化。 1)getInternalDisplayToken:获取显…...

3101. 交替子数组计数 Medium
给你一个 二进制数组 nums 。 如果一个 子数组 中 不存在 两个 相邻 元素的值 相同 的情况,我们称这样的子数组为 交替子数组 。 返回数组 nums 中交替子数组的数量。 示例 1: 输入: nums [0,1,1,1] 输出: 5 解释&…...

Linux系统基础命令行指令——Ubuntu
基础指令 更新指令 sudo apt update sudo apt upgrade 切换超级管理员 su root 切换路径 //相对、绝对 cd 路径回上一级路径 cd ..cd ../.. 退两级路径 查看当前目录 pwd查看指定路径内容 ls //常见搭配 ls -al 创建目录 mkdir 路径 创建文件 touc…...

qt 读取配置文件
在Qt中读取配置文件,主要有以下几种方法: 使用QFile和QTextStream类: 这种方法适用于读取任意文本文件,包括配置文件。使用QFile的open()方法打开配置文件。使用QTextStream的readLine()方法逐行读取配置数据。使用QXmlStreamRea…...

拉格朗日插值法【python,算法】
拉格朗日插值是一种在数值分析中用来构建通过一系列已知数据点的多项式插值的方法。这种方法以 18 世纪的法国数学家约瑟夫拉格朗日命名。当给定一组离散的数据点(𝑥_0,𝑦_0),(𝑥_1,𝑦_1),...,(𝑥_𝑛,&…...

定个小目标之刷LeetCode热题(41)
338. 比特位计数 给你一个整数 n ,对于 0 < i < n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n 1 的数组 ans 作为答案。 今天看一下这道简单题,主要考查位运算,代码如下 class Solution {pu…...

Kotlin中的关键字
Kotlin 中的关键字可分为几个大类: 声明/定义关键字: class:用于定义类interface:用于定义接口object:用于声明对象,Kotlin中实现单例模式的关键字fun:用于声明函数var:用于声明可变…...

LabVIEW新能源汽车电池性能测试系统
新能源汽车的核心部件之一是电池,其性能直接关系到整车的续航里程、安全性和寿命。为了确保电池的性能和可靠性,测试是必不可少的环节。本文介绍了一种基于LabVIEW的新能源汽车电池性能测试系统,通过LabVIEW与数据采集设备的无缝集成…...

Elasticsearch 实现 Word、PDF,TXT 文件的全文内容提取与检索
文章目录 一、安装软件:1.通过docker安装好Es、kibana安装kibana:2.安装原文检索与分词插件:之后我们可以通过doc命令查看下载的镜像以及运行的状态:二、创建管道pipeline名称为attachment二、创建索引映射:用于存放上传文件的信息三、SpringBoot整合对于原文检索1、导入依赖…...

深度学习赋能数据分析,联蔚盘云引领业务革新
一、引言 随着大数据时代的到来,深度学习技术正逐渐成为企业数据分析的新引擎。联蔚盘云凭借其在深度学习领域的深厚积累,为企业提供高效、精准的数据分析解决方案,助力企业实现业务革新与增长。 二、深度学习与数据分析的完美结合 联蔚盘…...

Arthas实战(5)- 项目性能调优
1、接口耗时查询:trace命令 trace 命令能主动搜索 class-pattern/method-pattern 对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路。 1.1 准备测试应用 新建一个 SpringBoot 应用,写一耗时久的代码&…...

昇思25天学习打卡营第7天|Pix2Pix实现图像转换
文章目录 昇思MindSpore应用实践基于MindSpore的Pix2Pix图像转换1、Pix2Pix 概述2、U-Net架构定义UNet Skip Connection Block 2、生成器部分3、基于PatchGAN的判别器4、Pix2Pix的生成器和判别器初始化5、模型训练6、模型推理 Reference 昇思MindSpore应用实践 本系列文章主要…...

单选多选提交问卷,代码示例
element中 需要对接口返回的数据进行分析。多选问题使用checkbox,单选题使用radio。 多选时可以绑定min/ma&am…...

mars3d加载wms服务或者wmts服务注意事项
1.wms只支持4326、3857、4490的标准切片,其他坐标系不支持 Mars3D三维可视化平台 | 火星科技 2.wmts同理,Mars3D三维可视化平台 | 火星科技 3.对应级别tilematrix找到的瓦片tilerow&tilecol这两个参数使用常见报错无效参考: 【Mars3d】…...

【机器学习】机器学习与自然语言处理的融合应用与性能优化新探索
引言 自然语言处理(NLP)是计算机科学中的一个重要领域,旨在通过计算机对人类语言进行理解、生成和分析。随着深度学习和大数据技术的发展,机器学习在自然语言处理中的应用越来越广泛,从文本分类、情感分析到机器翻译和…...

ubuntu优化
rootlocalhost:~# grep -E "^(PermitRootLogin|GSSAPIAuthentication|UseDNS)" /etc/ssh/sshd_config PermitRootLogin yes GSSAPIAuthentication no UseDNS norootlocalhost:~# systemctl restart sshd#此时就可以设置root密码了rootlocalhost:~# passwd New passw…...

使用 HBuilder X 进行 uniapp 小程序开发遇到的问题合集
文章目录 背景介绍问题集锦1. 在 HBuilderX 点击浏览器运行时,报 uni-app vue3编译器下载失败 安装错误2.在 HBuilderX 点击微信小程序运行时,报 微信开发者工具打开项目失败,请参阅启动日志错误 背景介绍 HBuilder X 版本:HBui…...

Python爬虫获取视频
验证电脑是否安装python 1.winr输入cmd 2.在黑窗口输入 python.exe 3.不是命令不存在就说明python环境安装完成 抓取快手视频 1.在phcharm应用中新建一个项目 3.新建一个python文件 4.选择python文件,随便起一个名字后按回车 5.安装requests pip install requests 6.寻找需要的…...