写一个简单的 C++ 日志库 - cllogger(3)- CRT

通过上一篇 《写一个简单的 C++ 日志库 - cllogger(2)- 日期时间》我们已经掌握了如何通过 std::chrono 提供的日期时间工具转换时间参数为指定格式的字符串。

现在我们可以把各个参数信息拼装为 Entry 实例,交给 OutputMessage() 


void cllogger::LogInternal(Level level, std::chrono::system_clock::time_point timestamp, const WCHAR* source, const WCHAR* msg)
{auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(timestamp.time_since_epoch());auto seconds = std::chrono::duration_cast<std::chrono::seconds>(milliseconds).count();auto time = localtime(&seconds);WCHAR timestampSz[128];size_t len = _snwprintf_s(timestampSz,_TRUNCATE,L"%02i:%02i:%02i.%03llu",time->tm_hour,time->tm_min,time->tm_sec,milliseconds.count() % 1000);Entry entry = { level, std::wstring(timestampSz, len), source, msg };OutputMessage(entry);
}

 OutputMessage() 将完成最终的日志字符串拼接并输出


void cllogger::OutputMessage(Entry& entry)
{
#ifndef _DEBUGif (!m_LogToFile) return;
#endifconst WCHAR* levelSz =(entry.level == Level::Error) ? L"ERROR" :(entry.level == Level::Warning) ? L"WARNINIG" :(entry.level == Level::Fatal) ? L"Fatal" :L"DEBUG";// 拼装日志信息字符串std::wstring message = levelSz;message += L" (";message.append(entry.timestamp);message += L") ";message += entry.tag;message += L": ";message += entry.messsage;message += L'\n';// 输出日志信息字符串
}

日志消息的输出,可根据配置分别输出到调试窗口(或dbgview)、文件等。

先来实现输出到调试窗口,这里特指 windows 平台上 Visual studio 开发环境中,以 Debub 模式启动程序时底部显示的【输出】窗口。

在【输出】窗口中右键可以看到异常、单步筛选、模块加载、卸载、进程退出、线程退出、程序输出等信息都会输出到这里。

【程序输出】是指我们通过代码输出的信息,这里我们就要讲讲输出信息到【输出】窗口的两种方法:

1、OutputDebugString API 

    OutputDebugString(L"output message.");

如果我们希望只在debug版的时候才输出,则需要

#ifdef _DEBUG::OutputDebugString(L"DEBUG");
#endif // _DEBUG

2、 _RPTn 宏系列

_RPTn 中的n后缀指定args中的(即格式化数据的)参数个数,它可以是 0、1、2、3、4 或 5。_RPTWn 是对应的宽字符版本。

如,没有args时:

_RPTW0(_CRT_WARN, message.c_str());

有1个参数时

int foo = 3;
_RPTW1(_CRT_WARN, L"foo is %d", foo);

后续以此类推。

考虑编译器及配置的不同,下面的调用方式更为周密安全:

#ifdef _UNICODE
#ifdef _RPTW0_RPTW0(_CRT_WARN, foo);
#endif
#else_RPT0(_CRT_WARN, foo);
#endif

这二者的主要区别是, OutputDebugString 是系统API,任何时候都会执行消息输出;但 _RPTn 则是 CRT 的一部分,它仅仅在调试模式下,输出到  Visual studio 的【输出】窗口中,而 Relase 版则会被替换为空,对性能基本没有影响。

CRT(C Runtime Library)

什么是CRT

Microsoft C 运行时库 (CRT) 。为了提高C语言的开发效率,C标准定义了一系列常用的函数,称为C库函数。C标准仅仅定义了函数原型,并没有提供实现。因此这个任务留给了各个支持C语言标准的编译器。每个编译器通常实现了标准C的超集,称为C运行时库(C Run Time Library),简称CRT。对于VC++编译器来说,它提供的CRT库支持C标准定义的标准C函数,同时也有一些专门针对Windows系统特别设计的函数 
  

CRT 和 API 及操作系统之间的关系

CRT包含哪些内容

内容说明
启动、退出入口函数、及所依赖的函数
标准函数C语言标准、标准库所拥有的函数实现
I/OI/O的封装
堆的封装和实现
语言实现特殊功能的实现
调试实现调试功能的代码

由此看来,CRT是 Windows 上编程的基石,提供了方方面面的底层支持。

使用 CRT 相关的功能很简单,只需要引入 <crtdbg.h> 即可。

我们接下来再列举一个 CRT 应用的例子。

CRT 调试技术

要使用 CRT 调试库之一,必须链接 /DEBUG,并使用 /MDd、/MTd 或 /LDd 进行编译。即,必须处于调试模式下。

C++ 程序员经常会遇到的困难之一便是内存泄露。内存泄露的原因是使用new或malloc等函数分配内存,但没有正确的配对使用delete和free释放内存,就会造成程序所占用的内存越来越大的现象。

检查内存泄漏的原理是,在分配的数据一头一尾分别插入对应的标志数据,微软使用的是0xfd 0xfd 0xfd 0xfd,检查是否溢出直接检查这两个标志数据是否被修改即可判断。

例如,我们分配10个字节的内存

char* a = new char[10];

a 的地址为 0x01039099,查看内存 

可以看到数据两端都填充了0xfd,初始化分配的数据填充为0xcd。 

主动调用 _CrtDumpMemoryLeaks 检查泄露:

#include <crtdbg.h>int main()
{char* a = new char[10];_CrtDumpMemoryLeaks();
}

输出

捕获到了内存泄漏,且指明了内存地址和大小。

如果想输出泄露内存代码所在的文件名和行号,那就完美了,我们可以通过宏来做到

#define DEBUG_NEW new(_CLIENT_BLOCK, __FILE__, __LINE__) 
#define new DEBUG_NEW

效果: 

已经非常清晰明了了。我们再进一步,能否让内存泄露信息以弹出窗口的方式显示?完全可以,只需要通过 _CrtSetReportMode 设置报告现实的方式即可:

#include <crtdbg.h>int main()
{_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW | _CRTDBG_MODE_DEBUG);_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_WNDW | _CRTDBG_MODE_DEBUG);char* a = new char[10];_CrtDumpMemoryLeaks();
}

 效果:

是不是很简单就做到了内存泄露的检查,其实,通过CRT我们还可以做到程序退出时自动检查,甚至为了降低检查对程序性能的影响,我们还可以设置检查内存泄露的频率。

总结

CRT 作为 Windows 编程中不可或缺的一部分,提供了基本的函数和宏,善用 CRT 会简化开发,提供可靠性,提供层序性能,确保了程序的高效健壮,需要我们好好的把握。


参考

  • C runtime library reference | Microsoft Learn
  • _RPT, _RPTF, _RPTW, _RPTFW Macros | Microsoft Learn

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

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

相关文章

视频无水印批量下载软件|抖音视频提取工具

视频无水印批量下载软件 在当今社交媒体充斥着大量优质视频内容的时代&#xff0c;很多用户都希望能够轻松下载自己喜爱的视频进行收藏或分享。为了满足用户的需求&#xff0c;我们特别推出了一款专业的视频无水印批量下载软件&#xff0c;让您可以方便快捷地获取喜爱的视频内容…

最新梨花带雨网页音乐播放器二开优化修复美化版全开源版本源码下载

最新梨花带雨网页音乐播放器二开优化修复美化版全开源版本源码下载 梨花带雨播放器基于thinkphp6开发的XPlayerHTML5网页播放器前台控制面板,支持多音乐平台音乐解析。二开内容:修复播放器接口问题,把接口本地化,但是集成外链播放器接口就不本地化了,我花钱找人写的理解下…

[C语言]——内存函数

目录 一.memcpy使用和模拟实现&#xff08;内存拷贝&#xff09; 二.memmove 使用和模拟实现 三.memset 函数的使用&#xff08;内存设置&#xff09; 四.memcmp 函数的使用 C语言中规定&#xff1a; memcpy拷贝的就是不重叠的内存memmove拷贝的就是重叠的内存但是在VS202…

C++总结

数据类型 基本的内置类型 修饰符类型 C 允许在 char、int 和 double 数据类型前放置修饰符。 修饰符是用于改变变量类型的行为的关键字&#xff0c;它更能满足各种情境的需求。 类型限定符 函数 以把代码划分到不同的函数中。如何划分代码到不同的函数中是由您来决定的&am…

使用 Dify 和 AWS Bedrock 玩转 Anthropic Claude 3

本篇文章&#xff0c;聊聊怎么比较稳定的使用 Anthropic Claude 3&#xff0c;以及基于目前表现非常好的模型&#xff0c;来做一些有趣的 AI Native 小工具。 写在前面 在实际体验了半个多月&#xff0c;月初上线的 Anthropic Claude Pro 后&#xff0c;发现 Claude 3 系列模…

C语言中的联合和枚举(未完)

1、联合体 联合体类型的声明 像结构体⼀样&#xff0c;联合体也是由⼀个或者多个成员构成&#xff0c;这些成员可以不同的类型。但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫&#xff1a;共⽤体。因为所有变量公用…

在任何 Mac 上恢复永久删除照片的 5 种简单方法

Mac 为业余和专业摄影师提供了很多东西&#xff0c;从令人印象深刻的硬件到广泛的照片管理和编辑应用程序。它还提供了多种恢复丢失照片的方法&#xff0c;我们在本文中介绍了其中的五种方法&#xff0c;以帮助您避免潜在的灾难性情况。 Mac 上删除的照片去了哪里&#xff1f;…

如何快速搭建一个完整的vue2+element-ui的项目-二

技术细节-继续配置 提示&#xff1a;你以为这样就完了吗,其实还有很多东西需要我们自己手写的 例如&#xff1a; element-ui的配置样式重置配置src使用的配置elinst配置axios异步请求的二次封转配置语言国际化配置(这个看需求,我这里就不用配置了)vuex的配置mixins的配置开发环…

【Linux第三课-基础开发工具的使用】yum、vim、gcc/g++编译器、gdb、Make/Makefile编写、进度条程序、git命令行简单操作

目录 yum - 软件包管理器快速认识yum快速使用yumyum搜索yum安装yum卸载 yum的周边 - yum的整个生态问题 vim快速介绍vimvim的模式命令模式插入模式低行模式 常见模式 -- 命令、低行命令模式 -- 光标的移动命令模式 -- 复制粘贴、剪贴、删除命令模式 -- 小写/大写替换模式命令模…

TCP协议 及 重要机制

目录 1.TCP 协议报文格式 1.1.端口号 1.2 首部长度 和 选项 1.3 保留位 1.4 检验和 1.5 32位序号和确认序号 2. TCP的重要机制 2.1 确认应答 2.2 超时重传 2.3 连接管理 2.3.1 三次握手 2.3.2 四次挥手 2.4 滑动窗口 2.5 流量控制 2.6 拥塞控制 2.7 延时应答 2…

JAVA EE (计算机是如何工作的)

学前注意事项 出去面试的时候java岗位不需要懂前端&#xff08;会少量讲解&#xff09; 但是我们做项目的时候多少回用到一些前端的东西 1.什么是计算机 1.1前情提要 不仅仅只有电脑是计算机 计算机还不仅仅是电脑手机和平板 路由器 智能洗衣机 刷脸打卡机都可以说是计算…

Ubuntu18.04桌面版设置静态IP地址

引用: Ubuntu配置静态IP_ubuntu配置静态ip地址-CSDN博客 正文 默认Unbuntu 18.04 Desktop桌面版使用 netplan 管理网卡网络地址。使用Unbuntu 18.04 桌面版配置&#xff0c;可以通过桌面上的设置图标配置网卡的静态IP地址。 点击桌面右上角下拉框&#xff0c;点击“设置”按…

知乎x-zse-96逆向

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872 本文章…

JAVA每日面经——JVM篇(包含JVM优化)

&#x1f469;&#x1f3fd;‍&#x1f4bb;个人主页&#xff1a;阿木木AEcru &#x1f525; 系列专栏&#xff1a;《Docker容器化部署系列》 《Java每日面筋》 &#x1f4b9;每一次技术突破&#xff0c;都是对自我能力的挑战和超越。 目录 一、什么是JVM&#xff1f;二、JVM由…

酷开系统用电视为居家生活打开精彩窗口|酷开科技|酷开会员|

随着互联网的发展&#xff0c;电视也承载了更多的功能。相比于传统的电视&#xff0c;如今的智能电视屏幕更大、分辨率更高、色彩更加鲜艳&#xff0c;能够呈现出更加逼真的画面效果。当观众观看大屏电视时&#xff0c;仿佛置身于电影大幕的场景之中&#xff0c;感受到更为震撼…

html常见标签

width宽度 height高度 border边框 1px&#xff08;边框线条宽度&#xff09; solid&#xff08;实线&#xff09; red&#xff08;红色&#xff09; border-radius: 100px 边框圆角 background-color&#xff1a;red&#xff08;背景颜色为红色&#xff09; margin&#xf…

2024年最新Anaconda3 2024版中Jupyter Notebook安装

一、 Anaconda3 2024版下载 1.下载&#xff1a;Free Download | Anaconda 2.等待 解释&#xff1a;默认选择等等下载 &#xff0c;时间可能数分钟 3.安装 解释&#xff1a;打开刚刚下载的Anaconda Navigator&#xff0c;并如图安装低版本&#xff0c;高版本会直接报错 4. …

CSS学习笔记:transform属性实现元素的位移、旋转、缩放

位移 实现居中的两种方法 绝对定位的盒子在父盒子中实现居中效果有两种方法 法一&#xff1a;margin 其中&#xff0c;left和top的值分别为子盒子自身宽高的一半 法二&#xff1a;translate 实现过渡效果 translate常常配合hover和transition使用&#xff0c;以实现鼠标悬停…

微博修改密码后无法通过微博开放接口发送微博

生产环境&#xff0c;因密码修改导致授权失效致接口发送微博失效&#xff01;内部网站编辑完博文后无法发送微博。在修改密码时&#xff0c;有提示授权应用失效&#xff0c;操作人员不清晰情况&#xff0c;直接忽视。 微博应用开放接口----》微博转发博文接口文档 无示例 遗憾…

突破边界:Web3开启数字化社会的新纪元

引言 随着科技的不断进步和数字化社会的发展&#xff0c;Web3正逐渐成为了人们关注的焦点。作为新一代互联网的演进形态&#xff0c;Web3具有突破传统边界、实现去中心化的特点&#xff0c;被认为将开启数字化社会的新纪元。本文将深入探讨Web3的概念、特点、应用场景&#xf…