C語言中帶返回值的宏定義方式
2023-02-25 06:00:50
C語言中帶返回值的宏定義
相信大家在實際工作中,一定有遇到需要編寫一個宏定義,且希望它能帶返回值的場景吧?
比如我之前就遇到一個場景,早期的程式碼是使用函數實現的功能,現在想換成宏定義,但是又要保留之前呼叫函數的程式碼不動,這樣我就只能想辦法寫一個帶返回值的宏了。
宏定義編寫
直接上demo:
#include <stdio.h> /* always return 1 */ #define RETURN_MACRO() ({do {} while(0);1;}) #define RETURN_MACRO2() 1 /* return a+b */ #define A_PLUS_B_MACRO(a, b) ({int ret; ret = (a) + (b); ret;}) #define A_PLUS_B_MACRO2(a, b) ({int ret; ret = add((a), (b)); ret;}) int add(int a, int b) { return (a + b); } int main(int argc, const char *argv[]) { int a = 6; int b = 7; printf("Hello world !n"); printf("RETURN_MACRO: %dn", RETURN_MACRO()); printf("RETURN_MACRO2: %dn", RETURN_MACRO2()); printf("a + b = %dn", A_PLUS_B_MACRO(a, b)); printf("a + b = %dn", A_PLUS_B_MACRO2(a, b)); return 0; }
宏定義分析
為了分析宏定義的寫法,我們得知道宏定義最終被展開是什麼樣的。
我在之前的博文中有提到,使用gcc編譯器的話,可以在CFLAGS上加上-save-temps=obj這個編譯選項,這樣就可以得到預編譯處理之後的檔案,字尾名是.i。
我們使用編譯指令碼編譯之後,得到.i檔案如下:
//前面的內容忽略 # 3 "main.c" 2 # 12 "main.c" # 12 "main.c" int add(int a, int b) { return (a + b); } int main(int argc, const char *argv[]) { int a = 6; int b = 7; printf("Hello world !n"); printf("RETURN_MACRO: %dn", ({do {} while(0);1;})); printf("RETURN_MACRO2: %dn", 1); printf("a + b = %dn", ({int ret; ret = (a) + (b); ret;})); printf("a + b = %dn", ({int ret; ret = add((a), (b)); ret;})); return 0; }
從.i檔案我們可以看到,宏定義被正常展開,下面確認下功能是否正常。
宏定義驗證
我們執行編譯出來的可執行檔案:
return_macro$ ./test Hello world ! RETURN_MACRO: 1 RETURN_MACRO2: 1 a + b = 13 a + b = 13
驗證成功。
經驗總結
- 在C語言裡面,可以使用({aaa; bbb; ccc;})來實現宏定義帶返回值;這裡的返回值是最後一個;的值。
- 注意裡面的()和{}都不能少,否則可能會破壞程式碼的語法結構,導致得不到正確的答案。
C語言中一些宏定義和常用的函數
typeof 關鍵字
如果你是 C++ 程式設計師,應該接觸過 C++11 裡的 decltype 操作符,它的作用是自動推導表示式的資料型別,以解決泛型程式設計中有些型別由模板引數決定而難以(甚至不可能)表示的問題。
其實這個特性在 C 語言中也早有類似的實現,GNU C 標準中的一個擴充套件特性 typeof 作用與 decltype 類似。
__typeof__ (ret) errnum = (ret);
snprintf()函數的作用
#include<stdio.h> int snprintf(char* dest_str,size_t size,const char* format,...);
【函數功能】:
先將可變引數 “…” 按照format的格式格式化為字串,然後再將其拷貝至dest_str中。
如果格式化後的字串長度小於size,則將字串全部拷貝至dest_str中,並在字串結尾處加上‘