View more

View more

View more

### Image of the Day Submit

IOTD | Top Screenshots

### The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.

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

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

17 replies to this topic

### #1sweetRum  Members

Posted 24 September 2013 - 02:23 PM

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...");

### #2Brother Bob  Moderators

Posted 24 September 2013 - 02:30 PM

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.

### #3Servant of the Lord  Members

Posted 24 September 2013 - 02:40 PM

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"}

Edited by Servant of the Lord, 26 September 2013 - 12:31 PM.

It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #4sweetRum  Members

Posted 24 September 2013 - 04:17 PM

RemoveEmptySegments | RemoveWhitespacePadding | PreserveTextInQuotes

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

### #5SiCrane  Moderators

Posted 24 September 2013 - 04:21 PM

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

### #6Cosmic314  Members

Posted 24 September 2013 - 04:57 PM

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.

Edited by Cosmic314, 24 September 2013 - 05:06 PM.

### #7Khatharr  Members

Posted 24 September 2013 - 05:02 PM

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

YAHOO!!!!!

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.

### #8sweetRum  Members

Posted 24 September 2013 - 05:22 PM

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?

### #9Cosmic314  Members

Posted 24 September 2013 - 05:57 PM

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 )
{
++count;
}
return(count);
}

Edited by Cosmic314, 24 September 2013 - 05:57 PM.

### #10sweetRum  Members

Posted 24 September 2013 - 06:19 PM

i c. pretty cool, thank you.

### #11Servant of the Lord  Members

Posted 24 September 2013 - 06:20 PM

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?

If you're using C++, it's considered bad practice to use #define to declare constant values. That was something that was common 20 years ago, but people have learned that it's not a good idea (through many a trial and error - and I don't mean figuratively ).

Instead, people use 'const int'/'const unsigned' or enums to create permanently unchanging values. #defines have hidden dangers to them can cause bugs if they are overused (they aren't broken - they just sometimes behave in ways people don't expect resulting in obvious-in-hindsight but hard-to-locate bugs). Older books and tutorials, and older code libraries (like Win32) use alot of #defines.

C++ code doesn't need to know the difference between hexadecimal, decimal, octal, and binary. They are all just integers of some kind or another (maybe signed, maybe unsigned, depending on the context). C++ code itself doesn't care what human format we write our numbers in

The compiler, when compiling our code, converts our C++ language code into machine assembly.

In the exact same way, the compiler converts our human numbering systems into whatever format (binary) the computer cares about.

Try running this code:

#include <iostream>
using namespace std;

void myFunc(int someValue)
{
std::cout << "Value: " << someValue << std::endl;
}

int main()
{
myFunc(255);
myFunc(0xFF);
myFunc(0377);
return 0;
}


There are two things to note here:

1. The function didn't have to treat hexadecimal values any differently than 'normal' decimal values
2. The output from the functions were exactly the same (because dec 255 == hex FF == oct 377; the values were equivalent)

The code didn't care at all. From our perspective, we wrote each number differently. From the code's perspective, it was the exact same thing.

These numbering systems can be used interchangeably for different purposes, whenever it is more convenient to write in one system over another.

Edited by Servant of the Lord, 24 September 2013 - 06:27 PM.

It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #12Cosmic314  Members

Posted 24 September 2013 - 06:41 PM

If you're using C++, it's considered bad practice to use #define to declare constant values. That was something that was common 20 years ago, but people have learned that it's not a good idea (through many a trial and error - and I don't mean figuratively ).

Instead, people use 'const int'/'const unsigned' or enums to create permanently unchanging values. #defines have hidden dangers to them can cause bugs if they are overused (they aren't broken - they just sometimes behave in ways people don't expect resulting in obvious-in-hindsight but hard-to-locate bugs). Older books and tutorials, and older code libraries (like Win32) use alot of #defines.

Yeah, this is a good point.  Instead of making macros as I had for GET_FIELD, it's probably better to declare an inline function.  In ARM assembly I could rewrite that entire expression as one CPU instruction, so there's a good chance the compiler will do the same.

A question for you:  Let's say you have > 1,000,000 constants of which you use only a fraction, let's say 1000.  Will the compiler maintain a symbol table with all 1,000,000 entries or is it smart enough to strip away unused constants?

### #13Servant of the Lord  Members

Posted 24 September 2013 - 08:30 PM

A question for you:  Let's say you have > 1,000,000 constants of which you use only a fraction, let's say 1000.  Will the compiler maintain a symbol table with all 1,000,000 entries or is it smart enough to strip away unused constants?

I don't know, optimizations at the assembly level isn't an area I've looked into!

I've never really had anywhere near a million constants before - my projects are small hobbyist / indie developer PC games and tools, not AAA console games, so the occasional function-level and architectural-level optimizations are my projects have needed in the past.

It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #14Cosmic314  Members

Posted 24 September 2013 - 08:57 PM

I'm a little curious now.  I may have to try an experiment and see what happens.  In my day job I do embedded characterization.  The SoCs we develop have tens of thousands of memory mapped registers which are all defined in a massive include file as a series of defines.  If I convert them to constants and compile as a separate unit it might help with compile times.  But I can't keep all those definitions in the final linked file.  Ironically I don't have enough memory on the SoC itself to hold that number of constants.

Edited by Cosmic314, 24 September 2013 - 08:58 PM.

### #15Khatharr  Members

Posted 24 September 2013 - 10:24 PM

Compilers tend to strip things thst aren't used unless they have some reason to expect that it would be bad to do so. You could test it by writing a tiny program that declares a few constants snd then prints one out. Turn on optimization but leave debugging enabled, the just break somewhere and look the used constant up in memory to see if the unused ones are there as well.
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.

### #16RobTheBloke  Members

Posted 25 September 2013 - 03:45 AM

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

Or there is the old enum trick....

enum BinaryNumber
{
b00000000,
b00000001,
b00000010,
b00000011,
b00000100,
// snip
b11111100,
b11111101,
b11111110,
b11111111
};

enum Flags
{
None  = b00000000,
Flag1 = b00000001,
Flag2 = b00000010,
Flag3 = b00000100,
Flag4 = b00001000,
Flag5 = b00010000,
Flag6 = b00100000,
DefaultFlags = (Flag3 | Flag2 | Flag6)
};


personally I prefer shifts for flag values:


enum Flags
{
None  = 0,
Flag1 = 1 << 0,
Flag2 = 1 << 1,
Flag3 = 1 << 2,
Flag4 = 1 << 3,
Flag5 = 1 << 4,
Flag6 = 1 << 5,
DefaultFlags = (Flag3 | Flag2 | Flag6)
};


### #17RobTheBloke  Members

Posted 25 September 2013 - 03:55 AM

A question for you:  Let's say you have > 1,000,000 constants of which you use only a fraction, let's say 1000.  Will the compiler maintain a symbol table with all 1,000,000 entries or is it smart enough to strip away unused constants?

I don't know, optimizations at the assembly level isn't an area I've looked into!

I've never really had anywhere near a million constants before - my projects are small hobbyist / indie developer PC games and tools, not AAA console games, so the occasional function-level and architectural-level optimizations are my projects have needed in the past.

A million constants will only be included in the final exe if you use *each* constant in an assignment or comparison. It's no different to comparing or assigning a million constant int values (an enum is an int). Just because a 32bit integer can store 4 billion+ different values, does not mean those values will automatically end up in the exe. Since both scenarios are highly unlikely, it's not really worth worrying about. Well, I suppose there is one situation. If you happen to have a switch statement will 1 million possibilities, then in theory that might happen. In practice, if the switch-cases are listed in order of smallest -> largest, then the compiler may be able to do something clever with optimisation in that case (i.e. assume an integer expression, and remove the constants entirely). Either way though, this isn't something to worry about. Constants are a good thing, and if you need 1 million of them in a switch statement, then so be it (just don't ask me to maintain the code!)

(The above advice assumes C++ is being used. If it's a .NET language, and you're compiling a class library, then things may be different. It's still not worth worrying about though. Chances are 1 million integer constants are still more efficient than 1 million string comparisons!)

Compilers tend to strip things thst aren't used unless they have some reason to expect that it would be bad to do so. You could test it by writing a tiny program that declares a few constants snd then prints one out. Turn on optimization but leave debugging enabled, the just break somewhere and look the used constant up in memory to see if the unused ones are there as well.

There's no need to do this. The constants won't be there.

Edited by RobTheBloke, 25 September 2013 - 03:56 AM.

### #18Leandro GR  Members

Posted 25 September 2013 - 09:07 AM

I just think it's way easier to write and read this
enum MyFlags
{
Flag1 = 0x1,
Flag2 = 0x2,
Flag3 = 0x4,
Flag4 = 0x8,
Flag5 = 0x10,
Flag6 = 0x20,
Flag7 = 0x40,
Flag8 = 0x80
}
Than this
enum MyFlags
{
Flag1 = 1,
Flag2 = 2,
Flag3 = 4,
Flag4 = 8,
Flag5 = 16,
Flag6 = 32,
Flag7 = 64,
Flag8 = 128
}
Both ways are easy to do, if I use decimal I just have to double the last value, but with hexadecimal I just have to remember the sequence 1, 2, 4 and 8 as it will just repeat itself over and over, just adding zeros to the end

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.