Advertisement

Whats the added benefit of using hexadecimal?

Started by February 01, 2017 01:52 AM
17 comments, last by frob 7 years, 10 months ago

While reading someone else code, I noticed that they were using hexadecimal numbers instead of regular base 10. What is the added benefit of using hexadecimal in code (or even binary for that matter).

For example:


 
enum Behavior
{
    Flee     = 0x00001,
    Seek     = 0x00002,
    Wander = 0x00003
 
}
 
For regularly increasing numbers (1,2,3) not very much... For powers of two, hex is easier to read, e.g. these three are equivalent:

enum Flags               | enum Flags          | enum Flags
{                        | {                   | {
    first    = 0x00001,	 |     first    = 1,   |     first    = 1<<0,
    second   = 0x00002,	 |     second   = 2,   |     second   = 1<<1,
    third    = 0x00004,	 |     third    = 4,   |     third    = 1<<2,
    etc      = 0x00008,	 |     etc      = 8,   |     etc      = 1<<3,
    etc      = 0x00010,	 |     etc      = 16,  |     etc      = 1<<4,
    etc      = 0x00020,	 |     etc      = 32,  |     etc      = 1<<5,
    etc      = 0x00040,	 |     etc      = 64,  |     etc      = 1<<6,
    etc      = 0x00080,	 |     etc      = 128, |     etc      = 1<<7,
}                        | }                   | }
Advertisement
I prefer the 1<<X way myself (and very rarely other values such as 1<<X, 2<<X, 3<<X if there is a 2-bit field buried somewhere).
Hex is convenient for a few reasons. Like Hodgman mentioned, it can be more readable when dealing with bitmasks and flags.

I also like it because a byte can always be printed using exactly two hex digits. It makes formatting memory addresses and other large numbers more convenient, because your vanilla 32-bit pointer is always 8 hex digits long, and a 64-bit pointer is always 16 hex digits long.

If you print a 64-bit pointer as a base-10 integer, you have to potentially use 19 or 20 digits or so (I can't be arsed to figure it out offhand).


Another curious place that hex becomes useful is in editing binary files. Since every byte is 2 digits, you can arrange the file in a regular shape, and still edit each byte by hand. (This is - predictably - the tool known as a hex editor.)

Last but not least, don't forget your network addresses. Would you rather see 2130706433, or 0x7f000001? Hint: it's way easier to recognize one of those addresses as 127.0.0.1, the universal loopback address.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Hex is mostly of use when BYTE (8 bit) or NIBBLE (4 bit) boundries matter. All real programmers i know instantly know that 8 is bit 4, 3 is bits 1 and 2, 128 is bit 8, etc. What they can't do is tell anything about number like: 986895, 16777215 or 8388736, which happen to be the same as 0F0F0F, FFFFFF and 800080 in hex, which can be instanly an obviously recognized for things such as the RGB values of a middle grey color, full white, and a middle purple color respectively. Or for things like ASCII or Unicode values, or OPCODES of a computer.

8 is bit 4, 3 is bits 1 and 2, 128 is bit 8

You're off by one in bit number.

Lowest bit is bit number 0, which is 1 or 0x01, which is also 2^0, or 1 << 0.

By starting bit numbers by 0, the power, the shift, and the number of zeroes right of the 1 (ie the zeroes shifted in) all match.


dec =  hex = shift = power = bits
  1 = 0x01 = 1 << 0 = 2^0 = 0001
  2 = 0x02 = 1 << 1 = 2^1 = 0010
  4 = 0x04 = 1 << 2 = 2^2 = 0100
  8 = 0x08 = 1 << 3 = 2^3 = 1000

If you start counting at 1, you get "1 << (1-1)", and "2^(1-1)" in the first line which is more cumbersome to get right all the time.

Edit:

As others have noted, hex is mostly useful if you are interested in bits than the numeric value.

In fact, I read hex numbers always as bit patterns, and not as hex number. For example, "0xDA" I don't read as hex "D" and "A", I read it as bit patterns "1101" and "1010", I see the bit patterns expressed by the hex digits.

Advertisement
My personal preference is to only use hex to show that I'm caring more about the bits within the variable than the value itself.

For instance:
char some_flags = 0x0D; // <- This is more descriptive to me than...
char some_flags = 13; // ... this. The bits are important, the value is not. I see 0x0D as 00001101, not '13'. I see '13' as a number and not a string of bits.

C++ has binary literals now as well:


enum Flags {
  first    = 0b00000001, //1
  second   = 0b00000010, //2
  third    = 0b00000100, //4
  ...
}

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.

While reading someone else code, I noticed that they were using hexadecimal numbers instead of regular base 10. What is the added benefit of using hexadecimal in code (or even binary for that matter).

For example:


 
enum Behavior
{
    Flee     = 0x00001,
    Seek     = 0x00002,
    Wander = 0x00003
 
}
 


The reason it would be used in an enum like your example is when the programmer wants to combine the enum values.

When using powers of two the values look like this:

0x1 = 0001
0x2 = 0010
0x4 = 0100
0x8 = 1000

So if we have:


enum Behavior {
  Patrol = 0x1,
  Seek   = 0x2,
  Talk   = 0x4,
  Run    = 0x8
}

then behaviors can be combined by OR-ing the values.

For example if an NPC is patrolling and talking:

Behavior CurrentBehavior = Behavior.Patrol | Behavior.Talk; // CurrentBehavior is 0001 | 0100 -> 0101

or we can find out if a behavior is currently set by AND-ing the values:

if ((CurrentBehavior & Behavior.Talk) == Behavior.Talk) // ((0101 & 0100) == 0100) -> true

The reason it would be used in an enum like your example is when the programmer wants to combine the enum values.


But look closely at the example. ;)

 
enum Behavior
{
    Flee     = 0x00001, // Going to assume there are missing digits here.... In binary: 00000001
    Seek     = 0x00002, //In binary: 00000010
    Wander = 0x00003 // In binary: 00000011
 
}
In this case, Behavior.Flee | Behavior.Seek = Behavior.Wander. Behavior.Flee | Behavior.Wander = Behavior.Wander. Behavior.Seek | Behavior.Wander = Behavior.Wander. They have to be used separately, otherwise you just end up wandering.

This topic is closed to new replies.

Advertisement