[英]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.