专栏算法工具链【J6】工具链VP示例中日志打印解读

【J6】工具链VP示例中日志打印解读

Jade-self2025-03-01
56
0

1. 引言

在上一篇文章【J6】VP简介与单算子实操中,介绍了VP是什么,并以单算子rotate为例,介绍了VP API使用方法,其中有一些日志打印的代码显得特别高大上

作为对C++不那么熟悉的伙伴,可能会好奇:LOGE_AND_RETURN_IF到底是怎么写的呢?有没有什么门道可以介绍一下?

由于本人是属于对C++不那么熟悉的同学,下面会从我的视角来介绍这个问题,如果其中有错误或表述不当的地方,欢迎评论指正。

其实本文是为了服务于另外一篇文章:【J6】工具链VP示例为什么能运行

2. log_util.h代码解读

LOGE_AND_RETURN_IF是在log_util.h定义的一个宏,下面来具体看下log_util.h中的代码:

2.1 LOGx

来看一下日志宏定义

这些宏封装了 日志打印函数:

  • LOGI(Info):信息日志

  • LOGD(Debug):调试日志

  • LOGE(Error):错误日志

  • LOGW(Warning):警告日志

具体解释下其中一行:

LOGI(err_msg, ...) 定义了一个宏:

  • err_msg 是第一个参数

  • ... 表示可以接受变长参数。但... 仅是一个 占位符,它不能直接用于宏的展开。(在下面介绍个展开的例子)

HFLOGM_I("VP_TRANSFORMATION", err_msg, ##VA_ARGS):
  • HFLOGM_I是 hlog/logging.h 中提供的 具体日志实现

  • "VP_TRANSFORMATION" 是 日志模块名称,用于分类日志来源。

  • err_msg就是前面的LOGI中的err_msg

  • VA_ARGS 是一个 占位符的替代符,用于 填充 ... 传递的实际参数。

  • ##VA_ARGS 的作用是 在 VA_ARGS 为空时去掉前面的逗号,防止编译错误。
当调用:LOGI("Error code: %d", 404);
它会展开为:HFLOGM_I("VP_TRANSFORMATION", "Error code: %d", 404);
如果调用:LOGI("Simple message");
它会展开为:HFLOGM_I("VP_TRANSFORMATION", "Simple message");
其中 ##VA_ARGS 确保了 VA_ARGS 为空时不会出现额外的 ,。(在下面介绍个展开的例子)

2.2 LOGE_AND_RETURN_IF宏

下面来解读LOGE_AND_RETURN_IF宏的写法:

这个宏 LOGE_AND_RETURN_IF 是一个常见的 防御式编程(Defensive Programming) 宏,如果 condition 为真,则:

  1. 记录错误日志 LOGE(err_msg, ##VA_ARGS)
  2. 返回 code

定义一个LOGE_AND_RETURN_IF宏时,do { ... } while (0)起到什么作用?
do { ... } while (0) 的作用是让整个宏块结构化,使它在语法上表现得像一个普通的语句,这样:确保 if 语句和 return 被视为一个整体,不会因为 if-else 结构导致错误。
  • 条件满足,触发错误日志并返回;当 ... 为空时,去掉前面的 ,,防止编译错误,示例(无可变参数)

展开后

##VA_ARGS 确保了 没有多余的 , 影响 LOGE 语法。
  • (带可变参数)

展开后

2.3 do { ... } while (0)作用

在前面有说do { ... } while (0) 可以:确保 if 语句和 return 被视为一个整体,不会因为 if-else 结构导致错误。

为什么do { ... } while (0) 能避免 if-else 结构导致的错误?if-else结构有什么问题?下面来看一下

do { ... } while (0) 的核心作用是让整个宏块在语法上表现得像一个单一语句,从而避免 if-else 结构中的 悬空 else(dangling else) 和 单行 if 语句的 bug。

2.3.1 if-else 结构的问题

如果 没有 do { ... } while (0),在 if-else 语句中 直接用 if 语句包裹宏时,可能导致 else 结构错误。错误示例如下:

未使用 do { ... } while (0) 定义宏

代码中调用宏

错误展开:

此时就会引入悬空else 的问题。

2.3.2 悬空else问题

错误现象:

C/C++ 规定:else 总是匹配最近的 if。

上一节中 else 错误地匹配了 if (x < -10),而不是 if (x < 0),导致:

  • x = -5 时,if (x < 0) 为真,但 if (x < -10) 为假,所以 LOGE_AND_RETURN_IF 不执行。

  • 然而 else 仍然执行,最终 printf("x is positive\n"); 被错误地执行!

解决方案:使用do { ... } while (0)结构。

2.4 NULLPTR_ERR(ptr) 宏

#ptr 是 字符串化(stringizing)运算符,它会把 ptr 变成字符串。

示例:

展开后:

输出:my_ptr is null pointer

2.5 LOGE_AND_RETURN_IF_NULL(ptr, code) 宏

这个宏会:

  • 检查 ptr 是否为 nullptr。

  • 如果 ptr == nullptr:

    • 记录日志,日志信息由 NULLPTR_ERR(ptr) 生成,例如 "ptr is null pointer"。

    • 返回 code 作为错误码。

3. 总结

本文主要介绍在VP 单算子示例中用到的日志打印的头文件应该怎么写,主要适用于和我一样C++基础学习用户~

算法工具链
社区征文技术深度解析杂谈
评论0
0/1000