在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何使用宏偷梁換柱

454398 ? 來源:alpha007 ? 作者:alpha007 ? 2022-11-15 17:33 ? 次閱讀

有些時(shí)候,一些原本的函數(shù)功能可能并不是我們想要的,于是就想著修改函數(shù),或者再封裝一層函數(shù)。

比如對一個(gè)函數(shù)包裝:

void func()

{

printf("hello/n");

}

// 包裝函數(shù)

void my_func()

{

printf("add/n");

func();

}

打印效果如下:

每打印一個(gè) hello 前面都會增加一個(gè) add。

這樣確實(shí)能達(dá)到效果,但是因?yàn)槎嗾{(diào)用了一次函數(shù),所以性能會部分下降,同時(shí)需要更大的棧空間,那么是否有一種更好的方式去達(dá)到相同的目的呢?

有的,那就是使用宏進(jìn)行偷梁換柱,達(dá)到貍貓換太子的目的。

我們以打印函數(shù)為例,對它進(jìn)行偷梁換柱。

一般的打印函數(shù)只會打印我們輸入給它的參數(shù),卻無法打印額外的信息,比如時(shí)間戳、函數(shù)名、文件名、行號等。簡單一點(diǎn),假如我們希望在打印我們的消息前,能添加時(shí)間戳和函數(shù)名,又該如何做呢?

簡單且易理解的偷梁換柱如下:

// 定義我們自己的打印函數(shù)格式

#define OSPREY_LOG(fmt, ...) rt_kprintf("<%08d>[%s] "fmt"/r/n",/

rt_tick_get(), __FUNCTION__, ##__VA_ARGS__)

#undef printf // 使 printf 在下面失去效用

// 重新定義,此時(shí)下面的所有 printf 是一個(gè)宏,而不是函數(shù)

#define printf(fmt, ...) OSPREY_LOG(fmt, ##__VA_ARGS__)

void osprey_task(void *parameter)

{

uint32_t nbr = 0;

while(1)

{

printf("hello, Osprey %u", nbr++);

rt_thread_delay(1);

}

}

原本我們的代碼里面使用的是 printf 進(jìn)行打印,但自己比較懶,不想每次換平臺的時(shí)候都修改打印函數(shù)(比如 RT-Thread 使用 rt_kprintf 打印),或者怕替換的時(shí)候操作失誤,那么此時(shí)就可以使用這個(gè)技巧了。

我們先定義出我們自己的打印格式(關(guān)于這個(gè),魚鷹會專門寫一篇筆記介紹如何設(shè)計(jì)一個(gè)簡單實(shí)用的日志打印框架,里面會詳細(xì)介紹這些內(nèi)容,目前暫時(shí)拿來用就行),這個(gè)格式包含了時(shí)間戳信息、函數(shù)名信息。

之后,使用 #undef 這條預(yù)編譯指令取消掉 printf 的作用域,接下來的代碼將不再調(diào)用標(biāo)準(zhǔn)庫的函數(shù),而是使用我們自己定義的宏函數(shù) printf,所以我們使用 #define 重新定義 printf。

也就是說,#undef printf 指令后面的代碼將使用 宏函數(shù) printf ,而不是標(biāo)準(zhǔn)庫函數(shù) printf,這是一道分水嶺。

接下來看看打印的效果如何:

可以看到,在我們的 “hello,Osprey”之前,打印了我們需要的時(shí)間戳和函數(shù)名信息,完美!

通過這些信息,我們就可以知道打印的消息是在什么時(shí)候打印的,又是在哪個(gè)函數(shù)中打印的,定位問題將更加方便(當(dāng)然你也可以加入文件名和行號,看自己的需要了)。

通過以上三行代碼,我們成功且高效的完成了函數(shù)的再次封裝,并且除了這些代碼,不需要對后面的代碼做任何修改,萬一平臺換了,也只需要修改這些代碼就行。

現(xiàn)在再來一個(gè)稍微難理解一點(diǎn)的。

既然前面的代碼可以替換 printf 打印函數(shù),那么我們會想,是否可以替換 rt_kprintf 本身呢?

也就是說本來我的代碼就是用 rt_kprintf 函數(shù)打印的,我們是否可以對它進(jìn)行封裝呢?
所以接下來的代碼應(yīng)運(yùn)而生:

// 定義我們自己的打印函數(shù)格式

#define OSPREY_LOG(fmt, ...) rt_kprintf("<%08d>[%s] "fmt"/r/n",/

rt_tick_get(), __FUNCTION__, ##__VA_ARGS__)

#undef rt_kprintf // 使 rt_kprintf 在下面失去效用

// 重新定義,此時(shí)下面的所有 rt_kprintf 是一個(gè)宏,而不是函數(shù)

#define rt_kprintf(fmt, ...) OSPREY_LOG(fmt, ##__VA_ARGS__)

void osprey_task(void *parameter)

{

uint32_t nbr = 0;

while(1)

{

rt_kprintf("hello, Osprey %u", nbr++);

rt_thread_delay(1);

}

}

當(dāng)你測試后,你會發(fā)現(xiàn),打印效果和前面的代碼等同,也就是說,通過三條代碼,成功將 rt_kprintf 貍貓換太子了。

其實(shí)當(dāng)你理解了 #undef 和 #define,上面代碼是不難理解的,#undef 取消了 rt_kprintf 的定義,而 #define 又重新定義了 rt_kprintf,所以接下來的:

rt_kprintf("hello, Osprey %u", nbr++);

被替換成了 :

rt_kprintf("<%08d>[%s] "hello, Osprey %u"/r/n",/rt_tick_get(), __FUNCTION__, nbr++)

因?yàn)?rt_kprintf 函數(shù)已經(jīng)有了,最后編譯、鏈接的時(shí)候也就能順利通過了,爽!

當(dāng)然,有時(shí)候版本發(fā)布的時(shí)候,我們發(fā)現(xiàn)不再需要打印函數(shù)了,那么我們只要使用如下方式即可消除打印(文件開頭添加即可,注意 //):

這個(gè)騷操作,你學(xué)會了嗎?


審核編輯 黃昊宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4338

    瀏覽量

    62751
收藏 人收藏

    評論

    相關(guān)推薦

    C語言定義使用技巧

    寫好C語言,漂亮的定義很重要,使用定義可以防止出錯,提高可移植性,可讀性,方便性等等。下面列舉一些成熟軟件中常用的定義。
    發(fā)表于 07-29 09:35 ?1121次閱讀

    C語言中的

    定義是我們C語言學(xué)習(xí)中非常重要的內(nèi)容。一些基礎(chǔ)的用法大家都比較清楚了,我們簡單總結(jié)一下。1.定義的格式為:#define 標(biāo)識符 字符串。2.定義屬于預(yù)處理命令,在編譯過程中的預(yù)處理階段處理
    發(fā)表于 12-13 15:32

    offsetof與container_of詳解

    offsetof與container_of詳解 1.offsetof與container_of1.1、由結(jié)構(gòu)體指針進(jìn)而訪問各元素的原理通過結(jié)構(gòu)體整體變量來訪問其中各個(gè)元素,本
    發(fā)表于 10-13 16:35

    擴(kuò)展問題

    MPLAB IDIDV3.65和XC8HI,“擴(kuò)展工具”是一個(gè)方便的工具來查看在項(xiàng)目文件中的擴(kuò)展(右鍵單擊并選擇導(dǎo)航/視圖擴(kuò)展)。不幸的是,我發(fā)現(xiàn)了一個(gè)問題:當(dāng)我在文件中更改
    發(fā)表于 04-14 09:57

    什么是

    什么是示例的應(yīng)用
    發(fā)表于 12-15 07:34

    如何設(shè)計(jì)調(diào)試

    前言借調(diào)試的設(shè)計(jì),梳理下的用法重定向printf打印嵌入式設(shè)備基本會配置RS232串口作為調(diào)試IO接口,假設(shè)底層串口單字節(jié)輸出函數(shù)為SERIAL_PutChar(),利用fputc()和fputs()重定向printf函數(shù)void fputc(int byte, FI
    發(fā)表于 12-15 06:13

    C語言中的是什么

    第五章 性能優(yōu)化5.1 使用定義  在C語言中,是產(chǎn)生內(nèi)嵌代碼的唯一方法。對于嵌入式系統(tǒng)而言,為了能達(dá)到性能要求,是一種很好的代替函數(shù)的方法。  寫一個(gè)"標(biāo)準(zhǔn)"MIN ,這個(gè)
    發(fā)表于 12-15 08:20

    excel中的使用方法、技巧和步驟

    excel中的使用方法如下: 一、建立 二、執(zhí)行 三、編輯和刪除
    發(fā)表于 11-19 10:16 ?11.7w次閱讀
    excel中<b class='flag-5'>宏</b>的使用方法、技巧和步驟

    什么是,excel中的作用

    所謂,就是一些命令組織在一起,作為一個(gè)單獨(dú)命令完成一個(gè)特定任務(wù)。Microsoft Word中對定義為:“就是能組織到一起作為一獨(dú)立的命令使用的一系列word命令,它能使日常工作變得更容易”。Word使用
    發(fā)表于 11-19 10:36 ?5.5w次閱讀

    內(nèi)聯(lián)函數(shù)和定義的區(qū)別介紹

    定義是C語言提供的三種預(yù)處理功能的其中一種,這三種預(yù)處理包括:定義、文件包含、條件編譯。定義和操作符的區(qū)別是:定義是替換,不做計(jì)算,也不做表達(dá)式求解。
    發(fā)表于 12-15 15:33 ?2342次閱讀
    內(nèi)聯(lián)函數(shù)和<b class='flag-5'>宏</b>定義的區(qū)別介紹

    之剖析

    本講座將探討C預(yù)處理器及其預(yù)處理器處理。我們將探討一些較高級的示例,并且還會探討與有關(guān)的一些誤解,以及預(yù)處理器如何展開和對求值。這
    的頭像 發(fā)表于 06-07 13:46 ?2371次閱讀
    <b class='flag-5'>宏</b>之剖析

    當(dāng)使用參數(shù)調(diào)用時(shí),會將參數(shù)替換為主體

    在大多數(shù)定義示例中,每次出現(xiàn)的參數(shù)名稱都帶有括號,并且另一對括號通常會包圍整個(gè)定義,這是編寫最好的方式。舉個(gè)例子
    的頭像 發(fā)表于 11-16 16:41 ?2347次閱讀

    AD637 SPICE模型

    AD637 SPICE模型
    發(fā)表于 06-17 13:43 ?12次下載
    AD637 SPICE<b class='flag-5'>宏</b>模型

    基于select!的進(jìn)階用法

    Tokio 是一個(gè)基于 Rust 語言的異步編程框架,它提供了一組工具和庫,使得異步編程變得更加容易和高效。其中最重要的組件之一就是 select!。 select!是 Tokio 中的一個(gè)核心
    的頭像 發(fā)表于 09-19 15:35 ?694次閱讀

    如何規(guī)范和常量以及命名

    和常量 ◎ 定義和常量使用大寫字母或下劃線。 ◎ 用定義表達(dá)式時(shí),要使用完備的括號,如下: #define HEHE_AREA( a , b ) (( a ) * ( b )) ◎
    的頭像 發(fā)表于 12-07 14:49 ?794次閱讀
    主站蜘蛛池模板: 五月婷婷影视| 亚洲va中文字幕| 视频黄色在线| 在线观看jyzzjyzz| 在线免费色| 性欧美xxx 不卡视频| 日毛片| 蝌蚪自拍网二区| 影院成人区精品一区二区婷婷丽春院影视 | 777奇米四色米奇影院在线播放| 台湾一级毛片永久免费| 免费观看在线永久免费xx视频 | 日本在线观看成人小视频| 手机在线观看a| 欧美色天使| 电影一区二区三区| 国产免费一区二区三区| 最近免费| 国产毛片毛片精品天天看| h国产| 亚综合| 亚洲天堂网站| 亚洲欧美色图| 如色网| 国产美女作爱| 天天干天天做| 欧美三级免费网站| 一级伦奸视频| 麦克斯奥特曼在线观看| 小雪被老外黑人撑破了视频| 国产午夜精品久久久久| 波多野结衣久久国产精品| 日本在线不卡一区二区| 四虎成人免费网站在线| 国模私拍在线观看| 久久久午夜影院| 老司机亚洲精品影院在线| 三及毛片| 亚洲资源在线视频| 午夜cao| 天天看天天摸天天操|