带循环的宏是如何在C/C++中实际工作的
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);
整个混乱是因为两个ptr变量
预处理器不知道C。它对令牌进行操作。据预处理器所知,for
与rof
一样是一个令牌。
那么,宏后面的位呢?预处理器不知道这是for
语句的一部分。一旦看到cimg_for(
的闭合)
,就完成了。没有其他替代品。
在您的情况下,cimg_for(*this,ptrd,T)
设置:
img
至this
ptrs
至ptrd
T_ptrs
至T
(ptr类型)
这段代码很奇怪,顺便说一句:如果你有C++,你就不需要这些宏技巧。
这看起来不像C,但以下是宏在C:中的工作方式
宏关键字在整个代码中进行搜索。宏关键字将在编译前替换为其定义。如果是带参数的宏,则传递的参数将替换为定义中的参数。
在您的情况下,
cimg_for(*this,ptrd,T)
将变成以下内容:
for (T * ptrd = (*this)._data + (*this).size(); (ptrd--)>(*this)._data; )
在写这篇文章的时候,我首先复制了定义,然后用*this
替换了定义中的每个img
,然后用ptrd
替换了每个ptrs
,最后用T
替换了每个T_ptrd
。这就是宏定义告诉我要做的,也是预处理器在编译之前要做的。
在这个宏之后,有一个语句,所以最后,循环看起来如下:
for (T * ptrd = (*this)._data + (*this).size(); (ptrd--)>(*this)._data; )
*ptrd = (T)*(--ptrs);
宏不是函数。它们基本上是一个精心设计的"搜索和替换"。预处理器用宏的主体替换它找到宏的位置(在宏声明的范围内)。
一些gatchas:因为宏不像函数,所以像这样的东西会变得危险
#define SQUARE(A) A*A
int i = 2;
int j = SQUARE(++i);
k==9//oops!
或者这个
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);
相关文章:
- QSqlquery prepare()和bindvalue()不工作
- 仅使用绝对值对数组进行排序,并在C++中显示实际值
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 用于了解输入和输出流缓冲区实际工作方式的程序
- 有人可以解释速记赋值运算符的实际工作原理吗?
- 字符串文字到 char 数组的转换如何在C++中实际工作
- `std :: string :: find_last_of()如何实际工作
- 对等如何实际工作网络/端口明智
- Ctrl Z的实际工作方式
- 浮点计算在 C++ 中是如何实际工作的
- 噪声功能的实际工作原理
- 转换构造函数的实际工作方式
- 栅栏是如何在c++中实际工作的
- 如何检查驱动程序代码签名策略是否已启用并实际工作
- 在C++参数中的引用和指针如何实际工作?他们的固定协议/"rule"是什么?
- 带循环的宏是如何在C/C++中实际工作的
- 依赖于其他 slib 的静态库是否需要它们的实际'code'才能工作?
- C++:将WCHAR转换为LPCWSTR - 实际工作示例