1

In the existing code, there are a few "reasons" for a certain failure case. These "reasons" are #defined as follows:

#define STRING_NOT_FOUND   (1 << 0)
#define STRING_INVALID     (1 << 1)
#define STRING_TOO_LARGE   (1 << 2)
...etc

These are set using function setFailureReason(int reason);

What is the advantage in using shift operator while defining these constants as compared to using numbers, as shown below:

#define STRING_NOT_FOUND   1
#define STRING_INVALID     2
#define STRING_TOO_LARGE   4
ontherocks
  • 1,747
  • 5
  • 26
  • 43
  • 3
    It just makes the fact that the values are powers of 2 more explicit. – juanchopanza May 17 '13 at 06:55
  • 1
    If you're going to use numbers, it would probably be better to use hex: `#define A 0x01`, `#define B 0x02`, `#define C 0x04`, `#define D 0x08`, `#define E 0x10`, `#define F 0x20`, etc. There's some reason for having the values as single bits — presumably so that they can be combined with more than one of the bits being set at the same time. – Jonathan Leffler May 17 '13 at 07:08
  • Read: [What is the meaning of this declaration?](http://stackoverflow.com/questions/15708493/what-is-the-meaning-of-this-declaration/15708566#15708566) and [define SOMETHING (1 << 0)](http://stackoverflow.com/questions/15095350/define-something-1-0?answertab=votes#tab-top) And this exactly answer your question [App States with BOOL flags](http://stackoverflow.com/questions/8956364/app-states-with-bool-flags/8956606#8956606) – Grijesh Chauhan May 17 '13 at 12:29

4 Answers4

4

It gets more useful when you get to 1 << 24 or something like that, which most people don't know is 16777216.

In this particular case, I'm not sure why it's a "bitfield" at all - can it be STING_NOT_FOUND at the same time as STRING_INVALID and/or STRING_TOO_LARGE.

And proper C++ would be to use enum (even in C, that would be preferred).

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • +1 for mentioning enums. There is really no need for the `#define`s here. – juanchopanza May 17 '13 at 07:23
  • @juanchopanza Unless the constants are later used in preprocessor expressions. (Unlikely, given their names, but one never knows.) – James Kanze May 17 '13 at 07:50
  • 2
    And finally: _if_ they really are bitfields (which would account for the use of powers of two, but doesn't seem to correspond to the name), not only would they be enums, but one would probably override the `|` and `&` operator on them, so that `STRING_NOT_FOUND | STRING_INVALID` would have the enum type. – James Kanze May 17 '13 at 07:53
3

This is mainly used when the error code represents a bit field that whose values can be logically-ored (VALUE_A | VALUE_B).

Using shift operators increase readability and prevent someone inserting a new error code from using an existing combination of bits (i.e. 5 for instance).

May be wrong:

#define STRING_NOT_FOUND    1
#define STRING_INVALID      2
#define STRING_TOO_LARGE    4
#define STRING_SOMETHING_KO 5

May be better:

#define STRING_NOT_FOUND    (1 << 0)
#define STRING_INVALID      (1 << 1)
#define STRING_TOO_LARGE    (1 << 2)
#define STRING_SOMETHING_KO (1 << 3)
Matthieu Rouget
  • 3,289
  • 18
  • 23
2

The use of "powers of two" only really makes sense when you are looking at flags, of which 0..n might be combined. Each of the constants (or enum values) stands for a specific bit being set in the resulting decimal number.

For one, "powers of two" written as decimals become unwieldly once you get beyond a certain point, at which you have to start doing math. (For me, this is 8192 x 2. ;-) )

For example hardware documentation might state to "set bit #4 and #8 of the register". Consider:

// set bit #4 and #8
reg |= 272;

Or:

// set bit #4 and #8
reg |= 0x110;

Compared to:

// set bit #4 and #8
reg |= ( ( 1 << 4 ) | ( 1 << 8 ) )
DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • But of course, any experienced programmer would write this as `reg |= 0x110;`. One can argue that the use of shifts in your second expression is clearer, but it is mainly more verbose, and any experienced programmer will recognized the hexadecimal format (and if a number is given in hexadecimal, rather than decimal, it is because the individual bits are important, rather than the actual numerical value). – James Kanze May 17 '13 at 07:49
  • 1
    @JamesKanze: I take some exception of you casually labeling me as non-experienced programmer. ;-) I added your version to my answer. I would still much prefer the third version, because in this case, verbosity equals clarity. – DevSolar May 17 '13 at 08:52
1

The obvious difference is that using said operator, you will have natural sequence (0,1,2,3,4,5,...) compared to next powers of two (1,2,4,8,16,32,...). The first one is shorter (log10 n vs log10 2^n) and arguably easier to understand.

DevSolar also made a quite important point about knowing the number of the bit; I personally remember all powers of 2 up to 16, so I never really thought about it.

Also please note that in C++, const or constexpr variables are preferred, or, as Mats suggested, enumerations.

Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
  • Since these are just constants (which means, one could assign any number to them), wouldn't it be more easier to read as `#define STRING_NOT_FOUND 1 #define STRING_INVALID 2 #define STRING_TOO_LARGE 3` rather than in powers of 2? – ontherocks May 17 '13 at 07:02
  • 2
    @ontherocks: In this case, yes. However the pattern of using bitfields of error constants is so common that some people use them even where they *don't* make that much sense. ;) – DevSolar May 17 '13 at 07:20
  • 1
    @ontherocks Usually, when such constants are set as values of two it is so they can be combined using bitwise OR, and combinations thereof can be checked using bitwise AND. – juanchopanza May 17 '13 at 07:50