簡體   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