recently i understood at last how can i store more values in an int with bytwise operators,
also, i have read that #define directives are evil for a number of reasons.
one of them:

#define SEVEN 2 + 5

int result = SEVEN * 5;
cout << result;    // you would expect that the console prints 35, but it doesn't
/*
let's take a look why this happens:
the folowing line: int result = SEVEN * 5;
it is converted by the compiler to this:
int result = 2 + 5 * 5;    // this will printout 27, not 35 as expected
so, if you'd want a correct answer, you'd have to put 2 + 5 into brackets at the define redirective like this: #define SEVEN (2 + 5)
*/

usually, bytwise operators are used to store different values into one single variable
here is an example where we use an int to denote some flags:

// random flags, the meanning does not matter
#define FLAG_FAST         1 << 0
#define FLAG_VISIBILE     1 << 1
#define FLAG_BIG          1 << 2

// ... etc

// function to set some flags to an integer
void SetFlags( int &flags )
{
    if( ... )
        flags |= FLAG_FAST;
    if( ... )
        flags |= FLAG_BIG;
    if( ... )
        flags |= FLAG_VISIBLE;
}

int flags = 0;
SetFlags( flags );

// now we want to use our flags
if( flags & FLAG_BIG )
{
// do stuff
}
// ... etc

what i want to ask is
when we check for some flags like in this line: if( flags & FLAG_BIG ),
the compiler transforms that code into this: if( flags & 1 << 2 )
heh, would be this calculeted as if( (flags & 1) << 2 ), or as if( flags & (1 << 2) )

i've noticed that the compiler treats it as if( flags & (1 << 2) ) and i don't understand why. does the '<<' and '>>' operators have a bigger precedence than '&' operator?

Recommended Answers

All 6 Replies

All that macros do is basically text substitution, so this:

#define SEVEN 2 + 5
 
int result = SEVEN * 5;

is really the same as this:

#define SEVEN 2 + 5
 
int result = 2 + 5 * 5;

Applying the order of precedence for numeric operators like this, it is the same as

#define SEVEN 2 + 5
 
int result = 2 + (5 * 5);

since multiplication has precedence over addition. Caveat Programmer!

So, if you want the SEVEN macro to be evaluated as a unit, it should look like this:

#define SEVEN (2 + 5)
 
int result = SEVEN * 5;

i know that define redirectives only replace the defined object with the text after

------------------------------------------------------------------------------------
what i want to ask is
when we check for some flags like in this line: if( flags & FLAG_BIG ),
the compiler transforms that code into this: if( flags & 1 << 2 )
heh, would be this calculeted as 'if( (flags & 1) << 2 )', or as 'if( flags & (1 << 2) )'?

i've noticed that the compiler treats it as if( flags & (1 << 2) ) and i don't understand why. does the '<<' and '>>' operators have a bigger precedence than '&' operator?
---------------------------------------------------------------------------------
^
that is the part that i don't understand -|

Mostly, operator precedence is defined by the language standards, but precedence between operators of equal precedence is up to the compiler implementor. That's why I said "Caveat Programmer!" - define your macros as you intend them to be evaluated, scoping them accordingly. Otherwise, what works on one system or with one compiler, may not on another, or even the same platform and compiler after an update.

Another example of this situation is when arguments that are effectively function calls (including prefix/postfix increment/decrement operations) passed to a function have side effects. Since the order of evaluation of the arguments to a function are also implementor-defined, these side effects may cause the function to get arguments of values that are different that what you expect. Again, Caveat Programmer!

The << and >> operator do have higher precedence than the bitand & operator, see this table.

However, I would not recommend that you rely on operator precedence in that kind of fashion. If you need, absolutely need, to use a #define, then wrap everything with parentheses and avoid the problem:

#define FLAG_FAST         (1 << 0)
#define FLAG_VISIBILE     (1 << 1)
#define FLAG_BIG          (1 << 2)

In this case, however, you are defining those flags in a very impractical fashion. This is the more "usual" way, using hexadecimal numbers:

#define FLAG_FAST         0x00
#define FLAG_VISIBILE     0x01
#define FLAG_BIG          0x02
#define FLAG_FOO          0x04
#define FLAT_BAR          0x08
//...

But when I say that the above is "usual", I really mean that it is commonly found in C libraries or APIs, but not in C++ code. In C++, there are several alternatives that are safer and better. One is to use a const global variable (or static const data member of a class):

const unsigned int FLAG_FAST     = 0x00;
const unsigned int FLAG_VISIBILE = 0x01;
const unsigned int FLAG_BIG      = 0x02;

Another popular solution is to use an enum:

enum MyFlags {
  FLAG_FAST     = 0x00,
  FLAG_VISIBILE = 0x01,
  FLAG_BIG      = 0x02
};

And usually, the enums are nested in the class or namespace they are used in or for.

MACROs in C++ have their place for very special purposes that cannot be achieved by any other means and do require a simple text-replace preprocessing. But defining constants is definitely not part of the circumstances in which a #define is recommended or necessary.

The << and >> operator do have higher precedence than the bitand & operator, see this table.

However, I would not recommend that you rely on operator precedence in that kind of fashion. If you need, absolutely need, to use a #define, then wrap everything with parentheses and avoid the problem:

#define FLAG_FAST         (1 << 0)
#define FLAG_VISIBILE     (1 << 1)
#define FLAG_BIG          (1 << 2)

In this case, however, you are defining those flags in a very impractical fashion. This is the more "usual" way, using hexadecimal numbers:

#define FLAG_FAST         0x00
#define FLAG_VISIBILE     0x01
#define FLAG_BIG          0x02
#define FLAG_FOO          0x04
#define FLAT_BAR          0x08
//...

But when I say that the above is "usual", I really mean that it is commonly found in C libraries or APIs, but not in C++ code. In C++, there are several alternatives that are safer and better. One is to use a const global variable (or static const data member of a class):

const unsigned int FLAG_FAST     = 0x00;
const unsigned int FLAG_VISIBILE = 0x01;
const unsigned int FLAG_BIG      = 0x02;

Another popular solution is to use an enum:

enum MyFlags {
  FLAG_FAST     = 0x00,
  FLAG_VISIBILE = 0x01,
  FLAG_BIG      = 0x02
};

And usually, the enums are nested in the class or namespace they are used in or for.

MACROs in C++ have their place for very special purposes that cannot be achieved by any other means and do require a simple text-replace preprocessing. But defining constants is definitely not part of the circumstances in which a #define is recommended or necessary.

Nice explanation Mike!

that was what i needed to know.
also the additional information that you both gave me is useful
thx you very much

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.