简体   繁体   English

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

[英]How macros with loop actually work in C/C++

This is a piece of code that i directly took from CImg library trying to understand how it actually works inside这是我直接从 CImg 库中获取的一段代码,试图了解它在内部的实际工作方式

Macro is defined in line 628 as宏在第 628 行定义为

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

and CImg has a constructor called like this in line number 9035并且 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; }
}

I believe this is how macro will be used, but would like a second opinion我相信这就是宏的使用方式,但想要第二个意见

for (T_ptrs *ptrs = (img)._data + (img).size(); (ptrs--)>(img)._data; )
     *ptrd = (T)*(--ptrs);

the entire confusion is because of two ptrs variable整个混乱是因为两个 ptrs 变量

The preprocessor doesn't know C. It operates on tokens.预处理器不知道 C。它对令牌进行操作。 for is a token like rof , as far as the preprocessor knows.就预处理器而言, for是一个类似于rof的标记。

So, the bit that follows the macro?那么,跟随宏的位是什么? The preprocessor doesn't know that's part of a for statement.预处理器不知道这是for语句的一部分。 Once it's seen the closing ) of cimg_for( , it's done. No further replacements.一旦看到cimg_for(的结尾) ,就完成了。没有进一步的替换。

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

  • img to this imgthis
  • ptrs to ptrd ptrsptrd
  • T_ptrs to T (Type of ptrs) T_ptrsTT_ptrs类型)

This code is weird, BTW: If you have C++, you don't need these macro hacks.这段代码很奇怪,顺便说一句:如果你有 C++,你就不需要这些宏技巧。

This doesn't look like C, but here's how macros work in C:这看起来不像 C,但这里是宏在 C 中的工作方式:

Macro keyword is searched throughout the code.在整个代码中搜索宏关键字。 Macro keyword is replaced with its definition prior to compilation.宏关键字在编译之前替换为其定义。 If it is a macro with arguments, the passed arguments are replaced with the ones inside the definition.如果是带参数的宏,则传递的参数将替换为定义中的参数。

In your case, the:在你的情况下,:

cimg_for(*this,ptrd,T)

Will be turned into the following:将变成如下:

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

While writing that, I have first copied the definition, then replaced each img inside definition with *this , then replaced each ptrs with ptrd , and lastly each T_ptrd with T .虽然写的是,我已经先复制的定义,那么替换的每个img内部定义与*this ,然后替换的每个ptrsptrd ,最后每个T_ptrdT That's what macro definition told me to do, that's also what preprocessor does prior to compilation.这就是宏定义告诉我要做的,这也是编译前预处理器所做的。

After that macro thing, there is a statement, so in the end, the loop looks like the following:在那个宏之后,有一个语句,所以最后,循环如下所示:

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

Macros aren't functions.宏不是函数。 They are basically an elaborate "search and replace".它们基本上是精心设计的“搜索和替换”。 The preprocessor literally replaces where ever it finds the macro (within the scope that the macro is declared) with the body of the macro.预处理器从字面上用宏的主体替换它找到宏的位置(在宏声明的范围内)。

Some gatchas: Because macros are not like functions, things like this become dangerous一些陷阱:因为宏不像函数,所以这样的事情变得危险

#define SQUARE(A) A*A

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

k == 9 // oops! k == 9 // 哎呀!

or this或这个

int i = SQUARE(IncrediblyExpensiveFuncionThatReturnsAnInt());

That huge function gets called twice.这个巨大的函数被调用了两次。 Once for each A in the macro宏中的每个 A 一次

For more info on the dangers of macros and how they work, check out this有关宏的危险及其工作原理的更多信息,请查看

This这个

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

becomes变成

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