0

I'm trying to do something similar to this:

#include <iostream>

int main()
{
    std::cout << 1 << 5 << std::endl;
}

I expect 32 (1 shifted left by 5), but I get 15.

I am trying to use a macro like this:

#define BIT_SHIFT(x,y) x << y
...
cout << BIT_SHIFT(1, 5) << std::endl;

and this happens.

Why? How do I fix this?

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
  • 1
    Parentheses? Separate variable? – JVApen Jun 01 '19 at 18:22
  • 1
    You may want to improve your coding and use `inline` functions instead of macros. You have encountered one of the major issues with using macros. – Thomas Matthews Jun 01 '19 at 19:08
  • @ThomasMatthews I don't think `inline` functions work unless you have optimizations enabled. – S.S. Anne Jun 01 '19 at 19:26
  • 1
    Inline functions work regardless of the optimization levels. The keyword `inline` is a suggestion (recommendation) to the compiler. Most of the compilers I've worked with honor the `inline` suggestion. Basically, a function prefixed with the `inline` keyword. – Thomas Matthews Jun 01 '19 at 19:28
  • 1
    @JL2210 -- inline functions "work" just fine, regardless of optimization settings. If they don't get inlined they are still functions, and get called as functions. – Pete Becker Jun 01 '19 at 19:28

3 Answers3

7

Just use parentheses:

#include <iostream>

int main()
{
    std::cout << (1 << 5) << std::endl;
}

std::cout << 1 << 5 means "push to output stream first integer literal 1, followed by integer 5". However, adding parantheses changes the order of evaluation, and 1 << 5 is evaluated first, resulting in std::cout << 32 << std::endl; expression.

TK-421
  • 294
  • 1
  • 7
  • 26
Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
  • 1
    Formally, it's not order of evaluation; it's **grouping** (sometimes informally referred to as "associativity", but that's not what the language definition calls it). The `<<` operator groups left to right, so `std::cout << 1 << 5;` is treated as `(std::cout << 1) << 5;`. Since the stream operator `<<` returns the stream object, the second `<<` is, essentially, `std::cout << 5`. By adding parentheses you override that grouping, so you get `1 << 5` and that's what gets inserted into the stream. +1. – Pete Becker Jun 01 '19 at 19:26
5

Use parenthesis:

    std::cout << (1 << 5) << std::endl;

The reason is that the output ostream& operator<<(ostream&, const T&) overload chains the return values to call the function once more.

If you use parenthesis, the bitshift value is calculated first, and then passed to the overloaded output operator.


I am trying to use this in a macro: ...

Thus the above said your macro definition should look like:

#define BIT_SHIFT(x,y) ((x) << (y))

You may wonder why the extra parenthesis now. This is just safer writing macros. Think about someone tries to use your macro like:

 cout << BIT_SHIFT(1, 5*2) << std::endl;
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
0

I'm trying to do something similar to this:

#include <iostream>

int main()
{
   std::cout << 1 << 5 << std::endl;
}

You're right. You are trying to do something similar to that. However, the problem has nothing to do with the macro (I mean, that's a problem too, but more on that later). The problem is your goal isn't what you mean. You don't mean std::cout << 1 << 5 << std::endl;, you mean std::cout << (1 << 5) << std::endl; The difference is that the first breaks down into something like this:

std::cout << 1;
std::cout << 5;
std::cout << std::endl;

While what you want is something like this:

int i = 1 << 5;

std::cout << i;
std::cout << std::endl;

Or something to that effect.

The answer is simple: either use parenthesis in your cout statement, or put it in your macro (the better option):

// either 
cout << (BIT_SHIFT(1, 5)) << std::endl;
// or
#define BIT_SHIFT(x,y) (x << y)
...
cout << BIT_SHIFT(1, 5) << std::endl;

Also, as someone else suggested, you can even go a step further if you like and do this:

#define BIT_SHIFT(x,y) ((x) << (y))
...
cout << BIT_SHIFT(1, 5) << std::endl;

That way, if you do something weird in x or y, your code doesn't break.