0

This is a piece of code that i directly took from CImg library trying to understand how it actually works inside

Macro is defined in line 628 as

#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

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

asked Apr 24, 2014 at 19:26
3
  • Aww! That looks like a quite bad idea :-/ ... What about writing an inline (template) function instead of the macro? Commented Apr 24, 2014 at 19:31
  • 3
    The -E flag on gcc or g++ will show you the expanded macros. Commented Apr 24, 2014 at 19:32
  • Sometimes the type is called t, sometimes T. Commented Apr 24, 2014 at 19:34

4 Answers 4

4

The preprocessor doesn't know C. It operates on tokens. for is a token like rof, as far as the preprocessor knows.

So, the bit that follows the macro? The preprocessor doesn't know that's part of a for statement. Once it's seen the closing ) of cimg_for(, it's done. No further replacements.

In your case, cimg_for(*this,ptrd,T) sets:

  • img to this
  • ptrs to ptrd
  • T_ptrs to T (Type of ptrs)

This code is weird, BTW: If you have C++, you don't need these macro hacks.

answered Apr 24, 2014 at 19:33
Sign up to request clarification or add additional context in comments.

Comments

2

This doesn't look like C, but here's how macros work in 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. 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);
answered Apr 24, 2014 at 19:40

1 Comment

@Ayushchoubey You're welcome bro, your feedback is also most welcome
1

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!

or this

int i = SQUARE(IncrediblyExpensiveFuncionThatReturnsAnInt());

That huge function gets called twice. Once for each A in the macro

For more info on the dangers of macros and how they work, check out this

answered Apr 24, 2014 at 19:36

1 Comment

Not the answer to the actual question, but worth an upvote, since newcomers will profit from those simple examples that show what can easily go wrong when using macros.
1

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);
answered Apr 24, 2014 at 19:37

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.