带循环的宏实际上如何在C / C ++中工作

时间:2014-04-24 19:26:51

标签: c++ c macros c-preprocessor

这是我直接从CImg库中获取的一段代码,试图了解它在

中的实际工作原理

宏在第628行定义为

#define cimg_for(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size(); (ptrs--)>(img)._data; )

和CImg在第9035行中有一个名为this的构造函数

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变量

4 个答案:

答案 0 :(得分:4)

预处理器不知道C.它对令牌进行操作。 for是一个像rof这样的标记,只要预处理器知道。

那么,宏之后的位?预处理器不知道这是for语句的一部分。一旦看到)的结束cimg_for(,就完成了。没有进一步的替代。

在您的情况下,cimg_for(*this,ptrd,T)设置:

  • imgthis
  • ptrsptrd
  • T_ptrsT(ptrs类型)

这段代码很奇怪,顺便说一下:如果你有C ++,你就不需要这些宏观攻击。

答案 1 :(得分:2)

这看起来不像C,但这里是宏如何在C中工作:

在整个代码中搜索宏关键字。在编译之前,宏关键字将被其定义替换。如果它是带参数的宏,则传递的参数将替换为定义中的参数。

在您的情况下,:

cimg_for(*this,ptrd,T)

将变成以下内容:

for (T * ptrd = (*this)._data + (*this).size(); (ptrd--)>(*this)._data; )

在撰写时,我首先复制了定义,然后用img替换每个*this内部定义,然后用ptrs替换每个ptrd,最后每个{{} {1}} T_ptrd。这就是宏定义告诉我要做的事情,这也是预处理器在编译之前所做的事情。

在那个宏之后,有一个语句,所以最后,循环如下所示:

T

答案 2 :(得分:1)

宏不是函数。它们基本上是一个精心设计的“搜索和替换”。预处理器逐字地替换了宏的主体(在声明宏的范围内)与宏的主体的位置。

一些gatchas:因为宏不像函数,所以这样的事情变得危险

#define SQUARE(A) A*A

int i = 2;
int j = SQUARE(++i);

k == 9 // oops!

或者

int i = SQUARE(IncrediblyExpensiveFuncionThatReturnsAnInt());

这个巨大的函数被调用两次。一次为宏中的每个A

有关宏的危险及其工作原理的详细信息,请查看this

答案 3 :(得分:1)

这个

#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);