文章目錄
- 1 寫在前面
- 2 問題需求
-
3 代碼實踐
- 3.1 編寫代碼
- 3.2 結果驗證
- 4 經驗總結
- 5 參考鏈接
- 6 更多分享
1 寫在前面
宏定義在 C語言中,是一種很常見的語法;經常閱讀開源代碼,你會發現,使用好C語言的宏定義,真的可以寫出更加整潔,可讀性非常高的高質量代碼。
本文將描述一個需要使用宏定義技巧來解決的問題場景,希望對大家理解和使用C語言的宏定義有所幫助和提高。
2 問題需求
最近恰好在項目開發的過程中,遇到了一個有關宏定義的問題。項目運用的背景如下:
項目中有個頭文件中定義了一個宏定義,比如是 #define CFG_LOGGER_NAME uart
然后,在某個C文件中需要將這個宏定義轉換成對應的字符串類型,即為 “uart” ;很明顯,如果按以下的幾種方式定義,肯定得不到期望的結果:
方式1: #define CFG_LOGGER_NAME_STR "CFG_LOGGER_NAME"
方式2: #define CFG_LOGGER_NAME_STR #CFG_LOGGER_NAME
方式3: #define CFG_LOGGER_NAME_STR ##CFG_LOGGER_NAME
3 代碼實踐
3.1 編寫代碼
為了解決這個問題,特意再次去查看了有關C語言宏定義的語法,終于找到了解決方法,具體的思路是,需要用一個 “中間宏函數” 做轉換,我們用代碼來實踐一下。
#include
#include
#define TEST uart
#define TO_STR(x) #x
#define CFG_LOGGER_NAME uart
#define TO_STRING(x) #x
#define _CFG_LOGGER_NAME_STR(x) TO_STRING(x)
#define CFG_LOGGER_NAME_STR _CFG_LOGGER_NAME_STR(CFG_LOGGER_NAME)
/* 這三種都達不到需求 */
#define CFG_LOGGER_NAME_STR1 "CFG_LOGGER_NAME"
/* 語法錯誤:error: stray ‘#’ in program */
//#define CFG_LOGGER_NAME_STR2 #CFG_LOGGER_NAME
/* 語法錯誤: error: '##' cannot appear at either end of a macro expansion */
//#define CFG_LOGGER_NAME_STR3 ##CFG_LOGGER_NAME
int main(void)
{
printf("\r\n%s\r\n", TO_STR(TEST));
printf("\r\n%s\r\n", CFG_LOGGER_NAME_STR);
printf("\r\n%s\r\n", CFG_LOGGER_NAME_STR1);
//printf("\r\n%s\r\n", CFG_LOGGER_NAME_STR2);
//printf("\r\n%s\r\n", CFG_LOGGER_NAME_STR3);
return 0;
}
3.2 結果驗證
驗證環境如下:
recan@ubuntu:~$ uname -a
Linux ubuntu 5.4.0-65-generic #73-Ubuntu SMP Mon Jan 18 17:25:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
recan@ubuntu:~$
recan@ubuntu:~$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with:
Thread model: posix
gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
代碼編譯:
gcc -o test test.c
結果運行:
recan@ubuntu:~$ ./test
TEST
uart
CFG_LOGGER_NAME
查看宏定義展開后的預處理文件:
recan@ubuntu:~$ gcc -E -o test.i test.c | tail -n 20 test.i
# 499 "/usr/include/string.h" 3 4
# 4 "test.c" 2
# 22 "test.c"
# 22 "test.c"
int main(void)
{
printf("\r\n%s\r\n", "TEST");
printf("\r\n%s\r\n", "uart");
printf("\r\n%s\r\n", "CFG_LOGGER_NAME");
return 0;
}
我們可以看到宏代碼的展開是符合我們的預期的,也只有CFG_LOGGER_NAME_STR
這一種寫法是滿足我們問題需求的。
4 經驗總結
- 宏定義看似很簡單,沒實踐出來的時候,有時候會想不通為什么會這么被展開?
-
在gcc編譯器下查看宏定義被展開的內容使用的是
-E
選項。 - C語言宏定義中的 “#” 和 “##” 是有特殊用法的,必須要用于帶參數的宏定義中,否則會報語法錯誤。
- 留個疑問:為何加了一個中間宏函數轉了一道手,就能得到預期的內容?
5 參考鏈接
- C語言的宏定義
- 帶參數和不帶參數的宏定義
6 更多分享
架構師李肯
一個專注于嵌入式IoT領域的架構師。有著近10年的嵌入式一線開發經驗,深耕IoT領域多年,熟知IoT領域的業務發展,深度掌握IoT領域的相關技術棧,包括但不限于主流RTOS內核的實現及其移植、硬件驅動移植開發、網絡通訊協議開發、編譯構建原理及其實現、底層匯編及編譯原理、編譯優化及代碼重構、主流IoT云平臺的對接、嵌入式IoT系統的架構設計等等。擁有多項IoT領域的發明專利,熱衷于技術分享,有多年撰寫技術博客的經驗積累,連續多月獲得RT-Thread官方技術社區原創技術博文優秀獎,榮獲CSDN博客專家、CSDN物聯網領域優質創作者、2021年度CSDN&RT-Thread技術社區之星、RT-Thread官方嵌入式開源社區認證專家、RT-Thread 2021年度論壇之星TOP4、華為云云享專家(嵌入式物聯網架構設計師)等榮譽。堅信【知識改變命運,技術改變世界】!
歡迎關注我的github倉庫01workstation,日常分享一些開發筆記和項目實戰,歡迎指正問題。
同時也非常歡迎關注我的專欄,有問題的話,可以跟我討論,知無不答,謝謝大家。
-
C語言
+關注
關注
180文章
7598瀏覽量
136205 -
宏定義
+關注
關注
0文章
50瀏覽量
9001 -
RT-Thread
+關注
關注
31文章
1272瀏覽量
39924
發布評論請先 登錄
相關推薦
評論