C multiline macro
multiline macro
在TensorRT/samples/common/common.h
中定義了CHECK(status)
這個macro:
#define CHECK(status) \
do \
{ \
auto ret = (status); \
if (ret != 0) \
{ \
std::cerr << "Cuda failure: " << ret << std::endl; \
abort(); \
} \
} while (0)
以下是在TensorRT/samples/opensource/sampleMNIST/sampleMNIST.cpp
中調用該macro的方法:
cudaStream_t stream;
CHECK(cudaStreamCreate(&stream));
我們可以看到在除最後一行外的每行末尾都加上了\
。\
在這裡的作用是line continuition character,即行接續字元(行繼續符),必須有它我們才能跨行定義macro。要注意的是\
後面除了\n
外什麼都不能加,連也是。
如果沒有加上\
,會出現error: expected unqualified-id
的錯誤。
從以上代碼可以觀察到的另一個現象是:函數的主要部份外面被包上了do{} while(0)
。
如果把do{} while(0)
拿掉:
#define CHECK(status) \
auto ret = (status); \
if (ret != 0) \
{ \
std::cerr << "Cuda failure: " << ret << std::endl; \
abort(); \
} \
在編譯時會出現錯誤error: use of undeclared identifier 'ret'
。
為了避免這個錯誤,需要把{}
加回去:
#define CHECK(status) \
{ \
auto ret = (status); \
if (ret != 0) \
{ \
std::cerr << "Cuda failure: " << ret << std::endl; \
abort(); \
} \
}
在這種情況下,如果我們使用CHECK(0);
來調用它,那麼這將不會出現任何問題。
但是設想以下這種調用方式:
if(something)
CHECK(0);
else
xxx();
以上代碼經過前處理(替換macro)後會變成:
if(something)
{
auto ret = (status);
if (ret != 0)
{
std::cerr << "Cuda failure: " << ret << std::endl;
abort();
}
};
else
function2();
可以看到,if跟else之間被加入了一個;
,這是很明顯的語法錯誤,並將會導致error: expected expression
。
為了解決這個問題,我們實際上可以把CHECK(0);
末尾的;
拿掉,但是這樣一來,我們就必須時時刻刻記得哪些是一般的函數,哪些是macro定義的函數,並使用不同的方式來調用它們。
一個比較好的方式是在函數本體外包上do{} while(0)
,如此一來,CHECK(0);
末尾的;
就變成必須的,所以不會造成語法錯誤。
參考連結
Why do multi-line macros have backslashes at the end of each line?: