-1

I've only been studying C++ (and programming for that matter) for a week, so the question may lack the understanding of fundamental programming principles, but here goes nothing:

unsigned int bitFlags()
{
unsigned char option1 = 0x01; // hex for 0000 0001
unsigned char option2 = 0x02; // hex for 0000 0010
unsigned char option3 = 0x04; // hex for 0000 0100
unsigned char option4 = 0x08; // hex for 0000 1000
unsigned char option5 = 0x10; // hex for 0001 0000
unsigned char option6 = 0x20; // hex for 0010 0000
unsigned char option7 = 0x40; // hex for 0100 0000
unsigned char option8 = 0x80; // hex for 1000 0000

unsigned char myflags; // byte-size value to hold some combination of the above 8 options

myflags |= option1|option2|option3;

if (myflags&option8)
    return 1;
else
    return 0;
}

int main()
{
   std::cout << bitFlags() << "\n";
    return 0;
}

So, I set only 3 flags (option1, option2, option3). Now, the flag query works as expected (returns 1 for options 1/2/3, and 0 for the rest) up-until option7/8. Even though option7/8 are not set, the function returns 1. Which brings me to the conclusion that unsigned char myflags looks like this in binary: 1100 0000. Well then,

1) What's happening here? Why are 2 bits already in use? How is an unsigned char using 2 bits in the first place? Shouldn't the "highest" bit be reserved only for signed variables?

2) Why do we use bitwise assignment operator |= to set bitflags when it provides unexpected results. If we simply assign myflags = option3 | option2 | option3 it works as expected - the query for option7/8 returns 0.

(There's a high probability that I have no idea what I'm talking about!)

Anon
  • 109
  • 1
  • 8

2 Answers2

4

You did not initialize myflags to 0 so there is unknown junk in there before you or in the flags.

ScottMcP-MVP
  • 10,337
  • 2
  • 15
  • 15
0

In C and C++ if you define a variable1 of a primitive type2 without initializing it explicitly, it starts in an undefined state, which explains the behavior you see here: you "add" (|=) the flags to a variable in an undefined state, thus you get other stuff in addition to what you actually specified.

The "junk" in your case comes from what happened to be already there on the stack previously: it may come from a previous function call (before the main the C++ runtime runs its own share of initialization code), or the whole stack may start pre-filled with junk values exactly to help you spot problems like this (that's typical of debug builds).

If we simply assign myflags = option1 | option2 | option3 it works as expected

That's why here you are assigning option1 | option2 | option3, overwriting what was in myflags in first place.

How is an unsigned char using 2 bits in the first place? Shouldn't the "highest" bit be reserved only for signed variables?

The highest bit is used in signed variables to hold the sign3, in unsigned types you have all the bits available for your purposes.


  1. Exception: globals and static locals are zero-initialized automatically.
  2. Actually, any type without a user-provided constructor
  3. That's actually an implementation-dependent behavior.
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • Thank you, unfortunately I can't up-vote you due to the lack of reputation.By the way, I understand that we're overwriting `myFlags` by using a direct assignment. But is there something inherently wrong with this practice? Assuming you forget to initialize (and the compiler doesn't complain, like in my case) the function still works as expected. Is there any danger in doing a `myFlags=` initialization instead of `myFlags|=`? – Anon Mar 28 '15 at 14:07
  • @Anon: well, there's nothing intrinsically wrong - if what you intend to do is to discard previous flags that were in the variable :-) . Incidentally, your compiler is probably able to give you a warning for this problem, you just have to crank your warning level (`-Wall -Wextra` on gcc, `/W4` with VC++). – Matteo Italia Mar 30 '15 at 06:57