Zed的强大的调试宏

2023-12-19 11:28
文章标签 调试 强大 zed

本文主要是介绍Zed的强大的调试宏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

#为什么需要错误处理

大多数程序员假定错误不会发生,并且这一乐观的思想影响了他们所用和创造的语言。

C通过返回错误码或设置全局的errno值来解决这些问题,并且你需要检查这些值。
通过这种机制检查现存的复杂代码中,你所执行的东西是否发生错误。模式如下

  • 调用函数
  • 如果返回值出现错误(每次必须检查)
  • 清理创建的所有资源
  • 打印出所有可能有帮助的错误信息

接下来将专注于这些步骤的实现

实现错误机制意味着每个函数调用结束后都需要3~4行额外代码,太麻烦。使用一系列“调试宏”作为解决方案。

几个重要的认知:

  • 错误检查可以在代码里直接写出,不过通常需要3~4行
  • 利用宏(而不是函数)来实现是由许多优势的
    • 简洁
    • 错误处理时需要用到file:line信息,如果在函数内部执行这些会得到错误信息
    • goto函数的实现会相当麻烦
  • goto 可以和标签结合使用
  • 宏的使用也有相当多的技巧,与函数有异曲同工之妙,但在使用方式上更加灵活(某些方面)

宏定义

#ifndef __dbg_h__
#define __dbg_h__#include <stdio.h>
#include <errno.h>   //引入errno变量
#include <string.h>#ifdef NDEBUG       //可以通过宏定义来消除所有调试信息
#define debug(M, ...)
#else
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)//输出错误信息,文件名,行号等。其中:##__VA_ARGS__表示宏中...   可以类似调用printf使用debug
#endif#define clean_errno() (errno == 0 ? "None" : strerror(errno))#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)#define check(A, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }#define sentinel(M, ...)  { log_err(M, ##__VA_ARGS__); errno=0; goto error; }#define check_mem(A) check((A), "Out of memory.")#define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__); errno=0; goto error; }#endif

代码解释

<errno.h>头文件

errno不是一个库,而是一个全局变量。
当调用一些系统库函数时,他们可能会设置errno的值来指示错误的类型。
通常,成功完成函数调用时会置零。
使用实例

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>int main() {FILE *file = fopen("nonexistent_file.txt", "r");if (file == NULL) {perror("Error opening file");    //自动根据error输出错误信息,终端显示:Error opening file: No such file or directoryfprintf(stderr, "errno = %d\n", errno);  //输出到标准输出流,终端显示:error = xexit(EXIT_FAILURE);}// Use the file...fclose(file);return 0;
}

综上理解:errno是一个全局变量,可以用来获取函数执行失败后的错误信息代号。
通常搭配perrorfprintf(stderr, " xxx%dxxx " , errno)使用
搭配strerror(errno)使用,返回对应的错误字符串`

debug宏

#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)

输出错误信息到终端:__FILE__代表文件名,__LINE__代表行号,##__VA_ARGS__代表可变参数部分...
这里对于debug的使用类似于调用printf

  • M是想要输出的错误字符串,注意不带换行符。
  • 后续可变参数可以替换M 中格式化预留的内容。

实例:
debug("I am %d years old.", 37);
终端输出
DRBUG ex20.c:11: I am 37 years old

dbg.h

#ifndef __dbg_h__
#define __dbg_h__#include <stdio.h>
#include <errno.h>
#include <string.h>#ifdef NDEBUG
#define debug(M, ...)
#else
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#endif#define clean_errno() (errno == 0 ? "None" : strerror(errno))#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)   //以上三条用于输出错误、警告等信息。#define check(A, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }  //完成输出信息、置零errno、跳转知至error标签#define sentinel(M, ...)  { log_err(M, ##__VA_ARGS__); errno=0; goto error; }     //可以放在不应该执行的地方,如 default#define check_mem(A) check((A), "Out of memory.")#define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__); errno=0; goto error; }#endif

使用案例#include “dbg.h”

#include"dbg.h"
#include <stdlib.h>
#include <stdio.h>void test_debug()
{// notice you don't need the \ndebug("I have Brown Hair.");// passing in arguments like printfdebug("I am %d years old.", 37);              //debug调用类似printf
}void test_log_err()
{log_err("I believe everything is broken.");log_err("There are %d problems in %s.", 0, "space");     //调用类似printf,输出错误信息,包含行号等}void test_log_warn()
{log_warn("You can safely ignore this.");log_warn("Maybe consider looking at: %s.", "/etc/passwd");
}void test_log_info()
{log_info("Well I did something mundane.");log_info("It happened %f times today.", 1.3f);
}int test_check(char *file_name)
{FILE *input = NULL;char *block = NULL;block = malloc(100);check_mem(block); // should work               //check_mem紧跟在分配空间之后input = fopen(file_name,"r");check(input, "Failed to open %s.", file_name);      //check文件紧跟在打开文件之后free(block);fclose(input);return 0;error:                              //error用于清空可能分配出去的空间if(block) free(block);if(input) fclose(input);return -1;
}int test_sentinel(int code)
{char *temp = malloc(100);check_mem(temp);switch(code) {case 1:log_info("It worked.");break;default:sentinel("I shouldn't run.");}free(temp);return 0;error:if(temp) free(temp);return -1;
}int test_check_mem()
{char *test = NULL;check_mem(test);free(test);return 1;error:return -1;
}int test_check_debug()
{int i = 0;check_debug(i != 0, "Oops, I was 0.");return 0;
error:return -1;
}int main(int argc, char *argv[])
{check(argc == 2, "Need an argument.");test_debug();test_log_err();test_log_warn();test_log_info();check(test_check("ex20.c") == 0, "failed with ex20.c");  //check给条件码和错误信息check(test_check(argv[1]) == -1, "failed with argv");check(test_sentinel(1) == 0, "test_sentinel failed.");check(test_sentinel(100) == -1, "test_sentinel failed.");check(test_check_mem() == -1, "test_check_mem failed.");check(test_check_debug() == -1, "test_check_debug failed.");return 0;error:return 1;
}

注意使用到errno的check等宏一定要紧跟在需要判断的函数后面。如空间分配后,文件打开后。
check给条件码和错误信息。

这篇关于Zed的强大的调试宏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511993

相关文章

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

vscode中文乱码问题,注释,终端,调试乱码一劳永逸版

忘记咋回事突然出现了乱码问题,很多方法都试了,注释乱码解决了,终端又乱码,调试窗口也乱码,最后经过本人不懈努力,终于全部解决了,现在分享给大家我的方法。 乱码的原因是各个地方用的编码格式不统一,所以把他们设成统一的utf8. 1.电脑的编码格式 开始-设置-时间和语言-语言和区域 管理语言设置-更改系统区域设置-勾选Bata版:使用utf8-确定-然后按指示重启 2.vscode

IntelliJ IDEA - 强大的编程工具

哪个编程工具让你的工作效率翻倍? 在日益繁忙的工作环境中,选择合适的编程工具已成为提升开发者工作效率的关键。不同的工具能够帮助我们简化代码编写、自动化任务、提升调试速度,甚至让团队协作更加顺畅。那么,哪款编程工具让你的工作效率翻倍?是智能的代码编辑器,强大的版本控制工具,还是那些让你事半功倍的自动化脚本?在这里我推荐一款好用的编程工具:IntelliJ IDEA。 方向一:工具介绍 Int

起点中文网防止网页调试的代码展示

起点中文网对爬虫非常敏感。如图,想在页面启用调试后会显示“已在调试程序中暂停”。 选择停用断点并继续运行后会造成cpu占用率升高电脑卡顿。 经简单分析网站使用了js代码用于防止调试并在强制继续运行后造成电脑卡顿,代码如下: function A(A, B) {if (null != B && "undefined" != typeof Symbol && B[Symbol.hasInstan

php 7之PhpStorm + Nginx + Xdebug运行调试

操作环境: windows PHP 7.1.10 PhpStorm-2017.2.4 Xdebug 2.5.4 Xdebug helper 1.6.1 nginx-1.12.2 注意查看端口占用情况 netstat -ano //查看所以端口netstat -aon|findstr "80" //查看指定端口占用情况 比如80端口查询情况 TCP 0.0.0.0:8

【2025】基于Python的空气质量综合分析系统的设计与实现(源码+文档+调试+答疑)

博主介绍:     ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W+粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台的优质作者。通过长期分享和实战指导,我致力于帮助更多学生完成毕业项目和技术提升。 技术范围:     我熟悉的技术领域涵盖SpringBoot、Vue、SSM、HLMT

VS Code 调试go程序的相关配置说明

用 VS code 调试Go程序需要在.vscode/launch.json文件中增加如下配置:  // launch.json{// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information,