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 编译器选项

/W11 级:严重警告
/W22 级:重大警告
/W33 级:生产级别警告。 您应该始终至少使用这个。 也是较新的 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 2
 87 |  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:
  explicit
  Logger (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");
}

运行上面示例

附上原文链接
如果文章对您有用,请随手点个赞,谢谢!^_^

在这里插入图片描述

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

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

相关文章

系统架构设计师——计算机体系结构

分值占比3-4分 计算机硬件组成 计算机硬件组成主要包括主机、存储器和输入/输出设备。 主机&#xff1a;主机是计算机的核心部分&#xff0c;包括运算器、控制器、主存等组件。运算器负责执行算术和逻辑运算&#xff1b;控制器负责协调和控制计算机的各个部件&#xff1b;主存…

react+ts+antd项目搭建

前言&#xff1a; 基于ts语言创建react项目&#xff0c;node版本是v16.14.2 一、 脚手架创建项目 全局安装 npm install -g creacte-react-app创建项目file-management&#xff0c;ts需要添加–template typescript npx create-react-app file-management --template typesc…

如何搭建10万个H100 GPU的集群:电力、并行化、网络拓扑与成本优化

引言 在现代人工智能的发展中&#xff0c;构建大规模GPU集群是提升计算能力的关键手段。今天我们探讨如何搭建一个包含10万个H100 GPU的集群。这个项目不仅涉及巨大的资本支出&#xff0c;还面临电力供应、并行化处理、网络拓扑结构以及可靠性和恢复等多方面的挑战。通过深入分…

天命奇御下载

解压码/安装码 615634 天翼&#xff1a;https://cloud.189.cn/t/qAjmAnIB3eIv 链接: https://pan.baidu.com/s/1rArV_Q_pB-9U4kEDtWf_gQ 提取码: igaq 天命奇御/官方中文/整合V.2.3DLC伏虎迷蹤/完美学习版下载地址&#xff1a; 点击下载 原始地址:https://www.aiwanba.net/post…

在RT-Thread-Studio中添加arm_math库

1.在CMSIS\Lib\GCC中找到对应的库&#xff0c;如本文使用的libarm_cortexM4lf_math.a。将库拷贝到工程&#xff0c;并做如下图设置。搜索路径为库文件在项目中的实际位置。 2.将CMSIS\DSP\Include下的文件复制到工程目录中&#xff0c;并添加包含路径 3.添加宏定义&#xff0c…

APP自动更换包名和签名系统源码

APP自动更换包名和签名系统源码 系统通过对apk反编译&#xff0c;随机包名&#xff0c;随机签名&#xff0c;混淆代码等方式&#xff0c;回编译生成新的apk安装包通过系统智能自动处理&#xff0c;间隔5分钟&#xff08;可以自定义时间&#xff09;生成一个新包&#xff0c;通…

算法思想总结:优先级队列

一、最后一块石头的重量 . - 力扣&#xff08;LeetCode&#xff09; 我们每次都要快速找到前两个最大的石头进行抵消&#xff0c;这个时候用优先级队列&#xff08;建大堆&#xff09;,不断取堆顶元素是最好的&#xff01;每次删除堆顶元素后&#xff0c;可以自动调整&#xf…

IP地址:网络还是设备的标识符?

在数字化时代&#xff0c;IP地址已成为我们连接互联网、进行信息交流的基石。然而&#xff0c;关于IP地址的分配和来源&#xff0c;很多人可能并不清楚。它究竟是根据网络来分配&#xff0c;还是基于设备来赋予&#xff1f;下面跟着虎观代理小二一起来解析IP地址的奥秘&#xf…

高效使用 Guzzle:POST 请求与请求体参数的最佳实践

介绍 在现代爬虫技术中&#xff0c;高效发送 HTTP 请求并处理响应数据是关键步骤之一。Guzzle 是一个强大的 PHP HTTP 客户端&#xff0c;广泛应用于发送同步和异步请求。本文将介绍如何使用 Guzzle 发送 POST 请求&#xff0c;特别是如何传递请求体参数&#xff0c;并结合代理…

Windows系统安装分布式搜索和分析引擎Elasticsearch与远程访问详细教程

文章目录 前言系统环境1. Windows 安装Elasticsearch2. 本地访问Elasticsearch3. Windows 安装 Cpolar4. 创建Elasticsearch公网访问地址5. 远程访问Elasticsearch6. 设置固定二级子域名 前言 本文主要介绍如何在Windows系统安装分布式搜索和分析引擎Elasticsearch&#xff0c…

HandlerMethodArgumentResolver :深入spring mvc参数解析机制

❃博主首页 &#xff1a; <码到三十五> ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a; 搬的每块砖&#xff0c;皆为峰峦之基&#xff1b;公众号搜索(码到三十…

[k8s生产系列]:k8s集群故障恢复,etcd数据不一致,kubernetes集群异常

文章目录 摘要1 背景说明2 故障排查2.1 查询docker与kubelet状态2.2 查看kubelet服务日志2.3 重启docker与kubelet服务2.3.1 首先kubelet启动起来了&#xff0c;但是报错master节点找不到2.3.2 查询kubernetes集群服务&#xff0c;发现etcd与kube-apiserver均启动异常 2.4 etcd…

2024年中国网络安全市场全景图 -百度下载

是自2018年开始&#xff0c;数说安全发布的第七版全景图。 企业数智化转型加速已经促使网络安全成为全社会关注的焦点&#xff0c;在网络安全边界不断扩大&#xff0c;新理念、新产品、新技术不断融合发展的进程中&#xff0c;数说安全始终秉承科学的方法论&#xff0c;以遵循…

Rhino 犀牛三维建模工具下载安装,Rhino 适用于机械设计广泛领域

Rhinoceros&#xff0c;这款软件小巧而强大&#xff0c;无论是机械设计、科学工业还是三维动画等多元化领域&#xff0c;它都能展现出其惊人的建模能力。 Rhinoceros所包含的NURBS建模功能&#xff0c;堪称业界翘楚。NURBS&#xff0c;即非均匀有理B样条&#xff0c;是计算机图…

怎样在Python中使用oobabooga的API密钥,通过端口5000获取模型列表的授权

题意&#xff1a; oobabooga-textgen-web-ui how to get authorization to view model list from port 5000 via the oobas api-key in python 怎样在Python中使用oobabooga的API密钥&#xff0c;通过端口5000获取模型列表的授权 问题背景&#xff1a; I wish to extract an…

抬头显示器HUD原理及特性

HUD基本原理 抬头数字显示仪(Head Up Display)&#xff0c;又叫平视显示系统&#xff0c;它的作用&#xff0c;就是把时速、导 航等重要的行车信息&#xff0c;投影到驾驶员前风挡玻璃上&#xff0c;让驾驶员尽量做到不低头、不转头 就能看行车信息。 HUD成像为离轴三反的过程&…

代码随想录算法训练营第2天|LeetCode977,209,59

977.有序数组平方 题目链接&#xff1a; 977. 有序数组的平方 - 力扣&#xff08;LeetCode&#xff09; 文章讲解&#xff1a;代码随想录 视频讲解&#xff1a; 双指针法经典题目 | LeetCode&#xff1a;977.有序数组的平方_哔哩哔哩_bilibili 第一想法 暴力算法肯定是先将元素…

关于软件本地化,您应该了解什么?

软件本地化是调整软件应用程序以满足目标市场的语言、文化和技术要求的过程。它不仅仅涉及翻译用户界面&#xff1b;它包含一系列活动&#xff0c;以确保软件在目标语言环境中可用且相关。以下是您应该了解的有关软件本地化的一些关键方面&#xff1a; 了解范围 软件本地化是…

【软件测试】之黑盒测试用例的设计

&#x1f3c0;&#x1f3c0;&#x1f3c0;来都来了&#xff0c;不妨点个关注&#xff01; &#x1f3a7;&#x1f3a7;&#x1f3a7;博客主页&#xff1a;欢迎各位大佬! 文章目录 1.测试用例的概念2.测试用例的好处3. 黑盒测试用例的设计3.1 黑盒测试的概念3.2 基于需求进行测…

暗潮短视频:成都柏煜文化传媒有限公司

暗潮短视频&#xff1a;涌动的新媒体力量 在数字化时代的浪潮中&#xff0c;短视频以其独特的魅力和无限的潜力&#xff0c;迅速成为新媒体领域的一股强大力量。而在这片繁荣的短视频领域中&#xff0c;成都柏煜文化传媒有限公司“暗潮短视频”以其独特的定位和深邃的内容&…