繁体   English   中英

带循环的宏如何在 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);

整个混乱是因为两个 ptrs 变量

预处理器不知道 C。它对令牌进行操作。 就预处理器而言, for是一个类似于rof的标记。

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

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

  • imgthis
  • ptrsptrd
  • T_ptrsTT_ptrs类型)

这段代码很奇怪,顺便说一句:如果你有 C++,你就不需要这些宏技巧。

这看起来不像 C,但这里是宏在 C 中的工作方式:

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

在你的情况下,:

cimg_for(*this,ptrd,T)

将变成如下:

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

虽然写的是,我已经先复制的定义,那么替换的每个img内部定义与*this ,然后替换的每个ptrsptrd ,最后每个T_ptrdT 这就是宏定义告诉我要做的,这也是编译前预处理器所做的。

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

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM