about style - why use hex instead of int in this function

Started by
16 comments, last by Unnamed User 10 years, 7 months ago

this function is declared as such:


#define FLAGS_NONE (0x00000000)
#define FLAGS_01   (0x10000000)
#define FLAGS_02   (0x20000000)

...

contextSetString(int flags, API_FIELDS field, char *value);

When it is called, it looks like this:


contextSetString(FLAGS_NONE, API_ENVELOPE_FIELD, "fopfsmvfdp...");
Advertisement

Hexadecimal values are also integers. They just happen to have a written text-form that is more beneficial than decimal values when it comes to representing values where the individual bits of the value has a meaning. It is almost directly apparent which bits are set in a value from its hexadecimal notation than its decimal notation.

It's not hexadecimal instead of ints, hexadecimal is a way to represent ints just like decimal is. It's hexadecimal instead of decimal or octal or binary - but all four of those produce integers.

If C++ supported native binary literals, that would be even more preferable (note: binary literals will be in the new C++14 standard).

With binary literals, it'd look like:


enum Flags {None  =      0b,
            Flag1 =      1b,
            Flag2 =     10b,
            Flag3 =    100b,
            Flag4 =   1000b,
            Flag5 =  10000b,
            Flag6 = 100000b,
            DefaultFlags = (Flag3 | Flag2 | Flag6),
            etc... };

It more clearly displays that each flag takes up only a single bit, and shows what bit they take.

They aren't just going 1, 2, 3, 4, like normal enums or constants, because normal enums can only be used one at a time; either you're using EnumValueA, or you're using EnumValueB.

With bit flags, you want to be able to use multiple flags at once - any combination that makes sense.
So you do: (Flag2 | Flag5 | Flag3) using bitwise OR operator, not the && logical AND operator.

Regardless of the order OR'd together (Flag2 | Flag5 | Flag3) becomes 10110b.

Because of this great feature, every flag needs to take one single bit that it exclusively uses.

Here's an example paraphrased from my own code library:


StringList results = Seperate("red,   green   , , blue, \"text with, comma in it\"", ',', RemoveEmptySegments | RemoveWhitespacePadding | PreserveTextInQuotes);

results = {"red", "green", "blue", "text with, comma in it"}

RemoveEmptySegments | RemoveWhitespacePadding | PreserveTextInQuotes

So would those flags be equal to: PreserveTextInQuotes | RemoveEmptySegments | RemoveWhitespacePadding ?

For integral types, bitwise-or is both commutative and associative, so yes.

Hexadecimal also allows for easy decoding of bits:


0x0 = 0000   0x8 = 1000
0x1 = 0001   0x9 = 1001
0x2 = 0010   0xA = 1010
0x3 = 0011   0xB = 1011
0x4 = 0100   0xC = 1100
0x5 = 0101   0xD = 1101
0x6 = 0110   0xE = 1110
0x7 = 0111   0xF = 1111


Each hex digit represents four bits. If you have a representation of groups of 4 bits, such as a 32 or 64 bit number, the mental translation is easier to compute. For example, if you need to convert to bits it is just a matter of lookup on this table:


0xFEDCBA98 is:

1111 1110 1101 1100 1011 1010 1001 1000
F    E    D    C    B    A    9    8

The unsigned decimal representation of this number is:

4275878552

As an exercise, convert this decimal number to binary by hand. It's not a difficult mathematical problem but certainly more involved than simply looking up digits in a table. As folks have already mentioned, seeing hex should sort of train your brain to think of the data in terms of flag bits rather than as a mathematical number.

If C++ supported native binary literals, that would be even more preferable (note: C++ will in the C++14 standard).

YAHOO!!!!! laugh.png

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

I c, so you could pass a function many flags in any order using hexadecimal form and descriptive #define calls. And what would the syntax look like to parse the haxadecimal to determine which flags where set once in the body of the function?

The parsing depends on what you are given. Typically you have a mask and possibly a shift value. For example if you want bits 20:17 of a 32 bit number I'd use a macro:


#define GET_FIELD(d,m,s) ((d & m) >> s)

unsigned field = GET_FIELD(input,0x001E0000,17);  // The mask is probably recorded as a #define somewhere.

If you're only given the mask you can compute the shift:


unsigned get_shift(unsigned mask)
{
   // this routine spins forever if mask = 0x0
   unsigned count = 0;
   while( mask & 0x1 == 0 )
   {
      mask >>= 1;
      ++count;
   }
   return(count);
}

i c. pretty cool, thank you.

This topic is closed to new replies.

Advertisement