<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>
"); //-->

博客專(zhuān)欄

EEPW首頁(yè) > 博客 > 征程 6|工具鏈 VP 示例中日志打印解讀

征程 6|工具鏈 VP 示例中日志打印解讀

發(fā)布人:地平線(xiàn)開(kāi)發(fā)者 時(shí)間:2025-04-05 來(lái)源:工程師 發(fā)布文章

1.引言

在上一篇文章【征程 6】VP 簡(jiǎn)介與單算子實(shí)操中,介紹了 VP 是什么,并以單算子 rotate 為例,介紹了 VP API 使用方法,其中有一些日志打印的代碼顯得特別高大上

    LOGE_AND_RETURN_IF(src_mat.empty(), HB_UCP_INVALID_ARGUMENT,
                   "Read image {} failed", src_img.c_str());

作為對 C++不那么熟悉的伙伴,可能會(huì )好奇:LOGE_AND_RETURN_IF 到底是怎么寫(xiě)的呢?有沒(méi)有什么門(mén)道可以介紹一下?

由于本人是屬于對 C++不那么熟悉的同學(xué),下面會(huì )從我的視角來(lái)介紹這個(gè)問(wèn)題,如果其中有錯誤或表述不當的地方,歡迎評論指正。

其實(shí)本文是為了服務(wù)于另外一篇文章:【征程 6】工具鏈 VP 示例為什么能運行

2.log_util.h 代碼解讀

LOGE_AND_RETURN_IF 是在 log_util.h 定義的一個(gè)宏,下面來(lái)具體看下 log_util.h 中的代碼:

#ifndef VP_CODE_07_ROTATE_INCLUDE_UTIL_LOG_UTIL_H_
#define VP_CODE_07_ROTATE_INCLUDE_UTIL_LOG_UTIL_H_

#include <sstream>    //C++中標準頭文件,不做解釋
#include <utility>    //C++中標準頭文件,不做解釋

#include "hlog/logging.h"    // 地平線(xiàn)提供的頭文件,并不在當前目錄下,為什么能包含?

#define LOGI(err_msg, ...) HFLOGM_I("VP_TRANSFORMATION", err_msg, ##__VA_ARGS__)
#define LOGD(err_msg, ...) HFLOGM_D("VP_TRANSFORMATION", err_msg, ##__VA_ARGS__)
#define LOGE(err_msg, ...) HFLOGM_E("VP_TRANSFORMATION", err_msg, ##__VA_ARGS__)
#define LOGW(err_msg, ...) HFLOGM_W("VP_TRANSFORMATION", err_msg, ##__VA_ARGS__)

#define LOGE_AND_RETURN_IF(condition, code, err_msg, ...) \
 do {                                                    \
   if (condition) {                                      \
     LOGE(err_msg, ##__VA_ARGS__);                       \
     return code;                                        \
   }                                                     \
 } while (0)

#define LOGE_AND_RETURN_IF_NULL(ptr, code) \
 LOGE_AND_RETURN_IF(ptr == nullptr, code, NULLPTR_ERR(ptr))

#endif  // VP_CODE_07_ROTATE_INCLUDE_UTIL_LOG_UTIL_H_

2.1 LOGx

來(lái)看一下日志宏定義

#define LOGI(err_msg, ...) HFLOGM_I("VP_TRANSFORMATION", err_msg, ##__VA_ARGS__)
#define LOGD(err_msg, ...) HFLOGM_D("VP_TRANSFORMATION", err_msg, ##__VA_ARGS__)
#define LOGE(err_msg, ...) HFLOGM_E("VP_TRANSFORMATION", err_msg, ##__VA_ARGS__)
#define LOGW(err_msg, ...) HFLOGM_W("VP_TRANSFORMATION", err_msg, ##__VA_ARGS__)

這些宏封裝了 日志打印函數:

LOGI(Info):信息日志

LOGD(Debug):調試日志

LOGE(Error):錯誤日志

LOGW(Warning):警告日志

具體解釋下其中一行:

#define LOGI(err_msg, ...) HFLOGM_I("VP_TRANSFORMATION", err_msg, ##__VA_ARGS__)

LOGI(err_msg, …) 定義了一個(gè)宏:

err_msg 是第一個(gè)參數

… 表示可以接受變長(cháng)參數。但… 僅是一個(gè) 占位符,它不能直接用于宏的展開(kāi)。(在下面介紹個(gè)展開(kāi)的例子)

HFLOGM_I(“VP_TRANSFORMATION”, err_msg, ##VA_ARGS):

HFLOGM_I 是 hlog/logging.h 中提供的 具體日志實(shí)現

“VP_TRANSFORMATION” 是 日志模塊名稱(chēng),用于分類(lèi)日志來(lái)源。

err_msg 就是前面的 LOGI 中的 err_msg

VA_ARGS 是一個(gè) 占位符的替代符,用于 填充 … 傳遞的實(shí)際參數。

##VA_ARGS 的作用是 在 VA_ARGS 為空時(shí)去掉前面的逗號,防止編譯錯誤。

當調用:LOGI(“Error code: %d”, 404);

它會(huì )展開(kāi)為:HFLOGM_I(“VP_TRANSFORMATION”, “Error code: %d”, 404);

如果調用:LOGI(“Simple message”);

它會(huì )展開(kāi)為:HFLOGM_I(“VP_TRANSFORMATION”, “Simple message”);

其中 ##VA_ARGS 確保了 VA_ARGS 為空時(shí)不會(huì )出現額外的 ,。(在下面介紹個(gè)展開(kāi)的例子)

2.2 LOGE_AND_RETURN_IF 宏

下面來(lái)解讀 LOGE_AND_RETURN_IF 宏的寫(xiě)法:

#define LOGE_AND_RETURN_IF(condition, code, err_msg, ...) \
 do {                                                    \
   if (condition) {                                      \
     LOGE(err_msg, ##__VA_ARGS__);                       \
     return code;                                        \
   }                                                     \
 } while (0)

這個(gè)宏 LOGE_AND_RETURN_IF 是一個(gè)常見(jiàn)的 防御式編程(Defensive Programming) 宏,如果 condition 為真,則:

    記錄錯誤日志 LOGE(err_msg, ##VA_ARGS)

    返回 code

定義一個(gè) LOGE_AND_RETURN_IF 宏時(shí),do { … } while (0)起到什么作用?

do { … } while (0) 的作用是讓整個(gè)宏塊結構化,使它在語(yǔ)法上表現得像一個(gè)普通的語(yǔ)句,這樣:確保 if 語(yǔ)句和 return 被視為一個(gè)整體,不會(huì )因為 if-else 結構導致錯誤。

條件滿(mǎn)足,觸發(fā)錯誤日志并返回;當 … 為空時(shí),去掉前面的 ,,防止編譯錯誤,示例(無(wú)可變參數)

LOGE_AND_RETURN_IF(error, -1, "An error occurred");

展開(kāi)后

do {
   if (error) {
       LOGE("An error occurred");
       return -1;
   }
} while (0);

##VA_ARGS 確保了 沒(méi)有多余的 , 影響 LOGE 語(yǔ)法。

(帶可變參數)

LOGE_AND_RETURN_IF(value < 0, -1, "Invalid value: %d", value);

展開(kāi)后

do {
   if (value < 0) {
       LOGE("Invalid value: %d", value);
       return -1;
   }
} while (0);

2.3 do { … } while (0)作用

在前面有說(shuō) do { … } while (0) 可以:確保 if 語(yǔ)句和 return 被視為一個(gè)整體,不會(huì )因為 if-else 結構導致錯誤。

為什么 do { … } while (0) 能避免 if-else 結構導致的錯誤?if-else 結構有什么問(wèn)題?下面來(lái)看一下

do { … } while (0) 的核心作用是讓整個(gè)宏塊在語(yǔ)法上表現得像一個(gè)單一語(yǔ)句,從而避免 if-else 結構中的 懸空 else(dangling else) 和 單行 if 語(yǔ)句的 bug。

2.3.1 if-else 結構的問(wèn)題

如果 沒(méi)有 do { … } while (0),在 if-else 語(yǔ)句中 直接用 if 語(yǔ)句包裹宏時(shí),可能導致 else 結構錯誤。錯誤示例如下:

未使用 do { … } while (0) 定義宏

#define LOGE_AND_RETURN_IF(condition, code, err_msg, ...) \
   if (condition) {                                      \
       LOGE(err_msg, ##__VA_ARGS__);                     \
       return code;                                      \
   }

代碼中調用宏

if (x < 0)
   LOGE_AND_RETURN_IF(x < -10, -1, "x is too small");
else
   printf("x is positive\n");

錯誤展開(kāi):

if (x < 0)
   if (x < -10) {  
       LOGE("x is too small");  
       return -1;  
   }  // 這里的 `if` 結束
else  // 這個(gè) else 可能會(huì )匹配到錯誤的 if!
   printf("x is positive\n");

此時(shí)就會(huì )引入懸空 else 的問(wèn)題。

2.3.2 懸空 else 問(wèn)題

錯誤現象:

x = -5:
x is positive   // 這個(gè)輸出是不應該出現的!

C/C++ 規定:else 總是匹配最近的 if。

上一節中 else 錯誤地匹配了 if (x < -10),而不是 if (x < 0),導致:

x = -5 時(shí),if (x < 0) 為真,但 if (x < -10) 為假,所以 LOGE_AND_RETURN_IF 不執行。

然而 else 仍然執行,最終 printf(“x is positive\n”); 被錯誤地執行!

解決方案:使用 do { … } while (0)結構。

2.4 NULLPTR_ERR(ptr) 宏

#define NULLPTR_ERR(ptr) #ptr " is null pointer"

#ptr 是 字符串化(stringizing)運算符,它會(huì )把 ptr 變成字符串。

示例:

printf("%s\n", NULLPTR_ERR(my_ptr));

展開(kāi)后:

printf("%s\n", "my_ptr is null pointer");

輸出:my_ptr is null pointer

2.5 LOGE_AND_RETURN_IF_NULL(ptr, code) 宏

#define LOGE_AND_RETURN_IF_NULL(ptr, code) \
 LOGE_AND_RETURN_IF(ptr == nullptr, code, NULLPTR_ERR(ptr))

這個(gè)宏會(huì ):

檢查 ptr 是否為 nullptr。

如果 ptr == nullptr:

記錄日志,日志信息由 NULLPTR_ERR(ptr) 生成,例如 “ptr is null pointer”。

返回 code 作為錯誤碼。

3.總結

本文主要介紹在 VP 單算子示例中用到的日志打印的頭文件應該怎么寫(xiě),主要適用于和我一樣 C++基礎學(xué)習用戶(hù)~


*博客內容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀(guān)點(diǎn),如有侵權請聯(lián)系工作人員刪除。




相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>