CBreeze
CBreeze

Reputation: 2973

Flags in C/ set-clear-toggle

I am confused as to what the following code does, I understand Line 1 sets a flag, line 2 clears a flag and line 3 toggles a flag;

#include <stdio.h>
#define SCC_150_A 0x01
#define SCC_150_B 0x02
#define SCC_150_C 0x04
unsigned int flags = 0;

main () {
  flags |= SCC_150_A;  // Line 1
  flags &= ~SCC_150_B; // Line 2
  flags ^= SCC_150_C;  // Line 3
  printf("Result: %d\n",flags); // Line 4
}

What I don't understand is what the output of Line 4 would be? What is the effect of setting/clearing/toggling the flags on 0x01 0x02 and 0x04?

Upvotes: 0

Views: 2601

Answers (2)

Mario
Mario

Reputation: 36517

First of all, I'm going to use binary numbers, cause it's easier to explain with them. In the end it's the same with hexadecimal numbers. Also note that I shortened the variable to unsigned char to have a shorter value to write down (8 bits vs. 32 bits). The end result is similar, just without leading digits.

Let's start with the values:

0x01 = 0000 0001
0x02 = 0000 0010
0x04 = 0000 0100

So after replacing the constant/macro, the first line would essentially be this:

flags |= 0000 0001

This performs a bitwise or operation, a bit in the result is 1, if any of the input values is 1 at that position. Due to the initial value of flags being 0, this will work just like an assignment or addition (which it won't in general, keep that in mind).

flags: 0000 0000
op:    0000 0001
----------------
or:    0000 0001

The result is flags being set to 0000 0001.

flags &= ~0000 0010

Here we've got two operations, first there's ~, the bitwise complement operator. What this essentially does is flipping all bits of the value. Therefore 0000 0010 becomes 1111 1101 (0xfd in hex). Then you're using the bitwise and operator, where a result bit is only set to 1 if both input values are 1 at the specific position as well. As you can see, this will essentially cause the second bit from the right to be set to 0 without touching any other bit.

flags: 0000 0001
op:    1111 1101
----------------
and:   0000 0001

Due to this, the result of this operation is 0000 0001 (0x01 in hex).

flags ^= 0000 0100

The last operation is the bitwise exclusive or (xor), which will set a bit to 1 only if the input bits don't match (i.e. they're different). This leads to the simple behavior of toggling the bits set in the operands.

flags: 0000 0001
op:    0000 0100
----------------
xor:   0000 0101

In this case the result will be 0000 0101 (0x05 in hex).

For clarification on the last operation, because I think xor might be the hardest to understand here, let's toggle it back:

flags: 0000 0101
op:    0000 0100
----------------
xor:   0000 0001

As you can see, the third bit from the right is equal in both inputs, so the result will be 0 rather than 1.

Upvotes: 2

unwind
unwind

Reputation: 399949

The macros define constants that each require a single bit to be represented:

macro      hex  binary
======================
SCC_150_A  0x01    001
SCC_150_B  0x02    010
SCC_150_C  0x04    100

Initially flags is 0.

Then it has:

  1. Bit 0 set by the bitwise OR.
  2. Bit 1 cleared by the bitwise AND with the inverse of SCC_150_B.
  3. Bit 2 toggled (turning it from 0 to 1).

The final result is thus 1012, or 5 in decimal.

Upvotes: 3

Related Questions