How macros with loop actually work in C/C++ - c++

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

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.

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

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

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

Related

what is the correct Pointer to members definition? [duplicate]

This question already has answers here:
Pointer to class data member "::*"
(18 answers)
Closed 3 months ago.
i took the below code from a different question on stackoverflow, im not sure What do the lines int (Foo :: * ptr); and int (Foo :: * ptr) (); mean? Can anyone share some answers?
struct Foo {
int a;
int b;
};
int main ()
{
Foo foo;
int (Foo :: * ptr);
ptr = & Foo :: a;
foo .*ptr = 123; // foo.a = 123;
ptr = & Foo :: b;
foo .*ptr = 234; // foo.b = 234;
}
Member functions are almost the same.
struct Foo {
int a ();
int b ();
};
int main ()
{
Foo foo;
int (Foo :: * ptr) ();
ptr = & Foo :: a;
(foo .*ptr) (); // foo.a ();
ptr = & Foo :: b;
(foo .*ptr) (); // foo.b ();
}
Debugging to no avail
Pointer to members is a long story to tell. First we assume that you've known what a normal pointer is.
Pointer to members suggests that it can point to the specific member of any instance of class. There are two types of pointer to members, first to member variables and second to member functions.
Before that, the variables and functions can be static or non-static. For static ones, it's no other than normal global ones from the program's perspective, e.g. in Linux ELF, static data are stored in .data directly, where the global variables are also stored. From the angle of the programmers, they are just accessing a special global function / variable as well, just adding some Class::. So, the pointer to static member variable / function is just the same as the pointer to a normal variable / function.
Now let's talk about the non-static ones. Non-static members should always bind to some specific object, e.g. obj.a or obj.func() and Class::a or Class::func() is illegal. Then, is it possible to use a pointer to suggest that "I hope to point to a specific member of any instance, and when I want to use it, I will bind an instance"? That's what the pointer to members do.
Wait... you may think: "That bothers! Why can't I just use the .?". To maintain the consistency, we will go back to this question finally. Now we assume it's useful first, and see what syntax it uses.
class ClassOpTest
{
public:
int nsVar; // non-static variable.
void nsFunc(int){return;} // non-static function.
};
int ClassOpTest::* nsVarPtr = &ClassOpTest::nsVar;
void (ClassOpTest::*nsFuncPtr)(int) = &ClassOpTest::nsFunc;
int main()
{
ClassOpTest object2;
ClassOpTest* object2Ptr = &object2;
object.*nsVarPtr = 1; // equals to object.nsVar = 1;
object2.*nsVarPtr = 2; // equals to object2.nsVar = 2;
object2Ptr->*nsVarPtr = 3; // equals to object2.nsVar = 3;
// Note that these paratheses are necessary, considering the operation order.
// If there are not, nsFuncPtr() will be resolved first rather than object.*nsFuncPtr().
// That is, the compiler will regard the nsFuncPtr as a normal function (pointer)
// rather than pointer to member function, so "obj.*" is just a meaningless mess.
// All in all, no paratheses will cause compilation error.
(object.*nsFuncPtr)(1); // equals to object.nsFunc(1);
(object2Ptr->*nsFuncPtr)(2); // equals to object2.nsFunc(2);
return 0;
}
You may find it's troublesome to write types like this, so you can use deduced type in C++11 as:
using ClassOpTestIntPtr = decltype(&ClassOpTest::nsVar);
using ClassOpTestFuncPtr = decltype(&ClassOpTest::nsFunc);
ClassOpTestIntPtr nsVarPtr = &ClassOpTest::nsVar;
ClassOpTestFuncPtr nsFuncPtr = &ClassOpTest::nsFunc;
Notice that the decltype doesn't mean it always points to nsVar or nsFunc; it means the type same as them.
You may also think .* or ->* is oblique(me too!), then you can use std::invoke in C++17 like this :
std::invoke(nsVarPtr, object2) = 1; // equals to object.*nsVarPtr = 1;
std::invoke(nsVarPtr, &object2) = 2; // equals to object2Ptr->*nsVarPtr = 2;
// both work.
std::invoke(nsFuncPtr, object2, 1); // equals to (object.*nsFunc)(1);
std::invoke(nsFuncPtr, &object2, 2); // equals to (object2Ptr->*nsFunc)(2);
std::invoke is significantly useful, but that's not the point of the answer. In a nutshell, it will use corresponding operator when the second calling parameter varies.
Finally, why is it useful? In my point of view, that's mostly because the pointer only conveys the type, and the type may infer lots of members. For instance:
struct RGB
{
std::uint8_t r;
std::uint8_t g;
std::uint8_t b;
};
and I hope to blend two std::vector<RGB> using Intel's SIMD intrinsics. First for r, that is:
reg1 = _mm_set_epi16(RGBdata1[i + 7].r, RGBdata1[i + 6].r, RGBdata1[i + 5].r,
RGBdata1[i + 4].r, RGBdata1[i + 3].r, RGBdata1[i + 2].r,
RGBdata1[i + 1].r, RGBdata1[i].r);
reg2 = _mm_set_epi16(RGBdata2[i + 7].r, RGBdata2[i + 6].r, RGBdata2[i + 5].r,
RGBdata2[i + 4].r, RGBdata2[i + 3].r, RGBdata2[i + 2].r,
RGBdata2[i + 1].r, RGBdata2[i].r);
reg1 = _mm_mullo_epi16(reg1, alphaReg1);
reg2 = _mm_mullo_epi16(reg2, alphaReg2);
resultReg1 = _mm_add_epi16(reg1, reg2);
// for simplicity, code below omitted; there are also manys operation to get the result.
// ...
// store back
_mm_store_si128((__m128i*)buffer, resultReg1);
for(int k = 0; k < 16; k++)
{
outRGBdata[i + k].r = buffer[k];
}
So what about g and b? Oops, okay, you have to paste the code twice. What if you find some bugs and want to change something? You have to paste again for g and b. That suffers! If we use pointer to members, then :
using RGBColorPtr = std::uint8_t RGB::*;
void SIMDBlendColor(RGB* begin1, RGB* begin2,
RGB* outBegin, RGBColorPtr color,
__m128i alphaReg1, __m128i alphaReg2)
{
__m128i resultReg1, reg1, reg2;
alignas(16) std::uint8_t buffer[16];
reg1 = _mm_set_epi16((begin1 + 7)->*color, (begin1 + 6)->*color,
(begin1 + 5)->*color, (begin1 + 4)->*color,
(begin1 + 3)->*color, (begin1 + 2)->*color,
(begin1 + 1)->*color, begin1->*color);
reg2 = _mm_set_epi16((begin2 + 7)->*color, (begin2 + 6)->*color,
(begin2 + 5)->*color, (begin2 + 4)->*color,
(begin2 + 3)->*color, (begin2 + 2)->*color,
(begin2 + 1)->*color, begin2->*color);
reg1 = _mm_mullo_epi16(reg1, alphaReg1);
reg2 = _mm_mullo_epi16(reg2, alphaReg2);
resultReg1 = _mm_add_epi16(reg1, reg2);
// ...
_mm_store_si128((__m128i*)buffer, resultReg1);
for(int k = 0; k < 16; k++)
{
(outBegin + k)->*color = buffer[k];
}
return;
}
Then, you can just call like this :
SIMDBlendColor(RGBdata1.data() + i, RGBdata2.data() + i, outRGBdata.data() + i, &RGB::r, alphaReg1, alphaReg2);
SIMDBlendColor(RGBdata1.data() + i, RGBdata2.data() + i, outRGBdata.data() + i, &RGB::g, alphaReg1, alphaReg2);
SIMDBlendColor(RGBdata1.data() + i, RGBdata2.data() + i, outRGBdata.data() + i, &RGB::b, alphaReg1, alphaReg2);
Clean and beautiful!
BTW, I strongly recommend you to check iso-cpp-wiki for more information.

use of 'n' before deduction of 'auto' C++

I'm trying to have my function return 3 values (n, down and across) I've read online how 'auto' can be used but must be doing something wrong.
The function takes in a 2D vector of integers (as well as other variables) and checks for how many numbers are connected to board[0][0] such that they are the same number.
I've tried putting auto in front of the function inside the function itself, tried leaving it blank, tried just having chain = chainNodes(...) but I always seem to get an error. Here's the code:
tuple<int, int, int> chainNodes(vector<vector<int>> board, int originalNum,
unsigned int across, unsigned int down, int ijSum,
int n)
{
struct chain {
int n, down, across;
};
if(down + across > ijSum) {
ijSum = down + across;
} else if((down + across == ijSum) &&
((down - across) * (down - across) < (ijSum) * (ijSum))) {
ijSum = down + across;
}
board[down][across] = 0;
n += 1;
// Check below
if((down != (board.size() - 1)) && (board[down + 1][across]) == originalNum) {
down += 1;
auto [n, iPoint, jPoint] = chainNodes(board, originalNum, across, down, ijSum, n);
down -= 1;
}
// Check right, up and left (I've removed so its not too messy here)
return chain{n, down, across};
}
Sorry, I forgot to include the error message.
error: use of 'n' before deduction of 'auto'
It occurs on the line that uses auto.
Issue with
auto [n, iPoint, jPoint] = chainNodes(board, originalNum, across, down, ijSum, n);
is similar to
auto n = foo(n); // `foo(n)` uses `n` from `auto n`,
// not the one from outer scope as function parameter
The construct int a = a + 1; is legal but lead to UB as reading uninitialized variable.
That kind of construct allows legal and valid behavior void* p = &p;.
Your code has other errors and it is not clear for me expected behavior of the function.
So not sure if following is the correct fix, but you might want:
n = std::get<0>(chainNodes(board, originalNum, across, down, ijSum, n));

Preprocessor directive to simulate a notation

In C++, is there a methodology by means of the preprocessor to substitute for a variable name followed by an index number by: its name followed by '[' followed by the index number, followed by ']'?
As an example, if I write:
int main(void)
{
int var[64];
var0 = 0;
var1 = 1;
var2 = 2; // etc...
return 0;
}
Translation:
int main(void)
{
int var[64];
var[0] = 0;
var[1] = 1;
var[2] = 2; // etc...
return 0;
}
#define is going to be the closest you can get.
#define var0 var[0]
#define var1 var[1]
...
However, it should be noted if you're going to use the above, you may as well just do it manually in the first place, since you're typing everything out anyway.
No. Thanks to language creators! There is no way to make syntax analysis (string parsing) inside macro definition.
It would be the real hell to read such programs.

C++ FAQ example on inline vs. #define

There is an example on the FAQ to explain the difference between inline and #define. The code is here
and the link is: http://www.parashift.com/c++-faq/inline-vs-macros.html
Tried with Visual C++, both unsafe() and unsafe(f()) didn't increase i twice. Is there a mistake on the example?
The main idea of #define is that it is just a preprocessor directive, meaning that this:
#define unsafe(i) ( (i) >= 0 ? (i) : -(i) )
will preprocess your code before it is compiled, and will replace the statement
unsafe(x++);
with the following
((x++) >= 0 ? (x++) : -(x++));
Everytime x++ is evaluated, x gets incremented.
One possible reason why you have problems with getting this sample code right might be that you compile your code with optimizations that optimize out all the unused / unnecessary code.
If you don't use your x anywhere, then it is considered as unused, hence does not get included into compiled code.
Just tested the example, Check Eric Gopak's answer for the explanation:
// A macro that returns the absolute value of i
#define unsafe(i) \
((i) >= 0 ? (i) : -(i))
// An inline function that returns the absolute value of i
inline
int safe(int i)
{
return i >= 0 ? i : -i;
}
int countCalls = 0;
int f()
{
return countCalls++;
};
int main()
{
int x = 0;
int ans = 0;
ans = unsafe(x++); // Error! x is incremented twice
ans = unsafe(f()); // Danger! f() is called twice
// x = 2
// countCalls = 2
ans = safe(x++); // Correct! x is incremented once
ans = safe(f()); // Correct! f() is called once
// x = 3
// countCalls = 3
return 0;
}

How can I fix an int-to-bool warning in C++?

I get a warning in MSVC++ when I try to read an integer from a file and make a bool variable equal it.
accessLV[i] = FileRead(file1, i + 1);
(accessLV is an array of bools, FileRead is a function I made to decrease the syntax involved in reading from a file, i is because the statement is within a for loop)
I've tried using a static_cast:
accessLV[i] = static_cast<bool>(FileRead(file1, i + 1));
But I still get the warning. I've tried doing this (I'm not sure the exact term):
accessLV[i] = (bool)FileRead(file1, i + 1));
And the warning is still there. Is there anyway to get rid of the warning without making accessLV an array of ints?
NB: this is the syntax of FileRead, if it helps:
int FileRead(std::fstream& file, int pos)
{
int data;
file.seekg(file.beg + pos * sizeof(int));
file.read(reinterpret_cast<char*>(&data), sizeof(data));
return data;
}
How about
accessLV[i] = FileRead(file1, i + 1) != 0;
What you want to do is basically
accessLV[i] = (FileRead(file1, i + 1) != 0)
accessLV[i] = FileRead(file1, i + 1) != 0;
Above, you were casting from int to bool: if you use this, the result of the comparison is put in accessLV[i], so not type warnings occur.
As other posters have suggested, !=0 is what you need. I prefer a wrapper like this because I find it more readable:
// myutil.hpp
template< typename T >
inline bool bool_cast( const T & t ) { return t != 0; }
Which you would use in this case like this:
// yourcode.cpp
accessLV[ i ] = bool_cast( FileRead( file1, i + 1 ) );
This related question has additional discussion you might find useful.