[英]How macros with loop actually work in C/C++
這是我直接從 CImg 庫中獲取的一段代碼,試圖了解它在內部的實際工作方式
宏在第 628 行定義為
#define cimg_for(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size(); (ptrs--)>(img)._data; )
並且 CImg 在第 9035 行有一個像這樣調用的構造函數
template<typename t>
CImg(const t *const values, const unsigned int size_x, const unsigned int size_y=1,
const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false):_is_shared(false) {
if (is_shared) {
_width = _height = _depth = _spectrum = 0; _data = 0;
throw CImgArgumentException(_cimg_instance
"CImg() : Invalid construction request of a (%u,%u,%u,%u) shared instance from a (%s*) buffer "
"(pixel types are different).",
cimg_instance,
size_x,size_y,size_z,size_c,CImg<t>::pixel_type());
}
const unsigned int siz = size_x*size_y*size_z*size_c;
if (values && siz) {
_width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
try { _data = new T[siz]; } catch (...) {
_width = _height = _depth = _spectrum = 0; _data = 0;
throw CImgInstanceException(_cimg_instance
"CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
cimg_instance,
cimg::strbuffersize(size_x*size_y*size_z*size_c*sizeof(T)),size_x,size_y,size_z,size_c);
}
const t *ptrs = values + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
} else { _width = _height = _depth = _spectrum = 0; _data = 0; }
}
我相信這就是宏的使用方式,但想要第二個意見
for (T_ptrs *ptrs = (img)._data + (img).size(); (ptrs--)>(img)._data; )
*ptrd = (T)*(--ptrs);
整個混亂是因為兩個 ptrs 變量
預處理器不知道 C。它對令牌進行操作。 就預處理器而言, for
是一個類似於rof
的標記。
那么,跟隨宏的位是什么? 預處理器不知道這是for
語句的一部分。 一旦看到cimg_for(
的結尾)
,就完成了。沒有進一步的替換。
在您的情況下, cimg_for(*this,ptrd,T)
設置:
img
到this
ptrs
來ptrd
T_ptrs
到T
( T_ptrs
類型)這段代碼很奇怪,順便說一句:如果你有 C++,你就不需要這些宏技巧。
這看起來不像 C,但這里是宏在 C 中的工作方式:
在整個代碼中搜索宏關鍵字。 宏關鍵字在編譯之前替換為其定義。 如果是帶參數的宏,則傳遞的參數將替換為定義中的參數。
在你的情況下,:
cimg_for(*this,ptrd,T)
將變成如下:
for (T * ptrd = (*this)._data + (*this).size(); (ptrd--)>(*this)._data; )
雖然寫的是,我已經先復制的定義,那么替換的每個img
內部定義與*this
,然后替換的每個ptrs
與ptrd
,最后每個T_ptrd
與T
。 這就是宏定義告訴我要做的,這也是編譯前預處理器所做的。
在那個宏之后,有一個語句,所以最后,循環如下所示:
for (T * ptrd = (*this)._data + (*this).size(); (ptrd--)>(*this)._data; )
*ptrd = (T)*(--ptrs);
宏不是函數。 它們基本上是精心設計的“搜索和替換”。 預處理器從字面上用宏的主體替換它找到宏的位置(在宏聲明的范圍內)。
一些陷阱:因為宏不像函數,所以這樣的事情變得危險
#define SQUARE(A) A*A
int i = 2;
int j = SQUARE(++i);
k == 9 // 哎呀!
或這個
int i = SQUARE(IncrediblyExpensiveFuncionThatReturnsAnInt());
這個巨大的函數被調用了兩次。 宏中的每個 A 一次
有關宏的危險及其工作原理的更多信息,請查看此
這個
#define cimg_for(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size(); (ptrs--)>(img)._data; )
cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
變成
for (T *ptrd = (*this)._data + (*this).size(); (ptrd--)>(*this)._data; )
*ptrd = (T)*(--ptrs);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.