Thread: Bit fields and hex

  1. #1
    Registered User
    Join Date
    Sep 2014
    Posts
    26

    Question Bit fields and hex

    Hello!

    When studying OpenGL, I noticed that constants are defined as such:

    Code:
    #define GL_CONSTANT_1 0x01 // 1 = 00000001
    #define GL_CONSTANT_2 0x02 // 2 = 00000010
    #define GL_CONSTANT_3 0x04 // 4 = 00000100
    I also read about bit fields, and, if I have understood them correctly, they work like this:

    Code:
    typedef struct
    {
            unsigned char one : 1;
            unsigned char two : 1;
            // ...
            unsigned char eight : 1;
    } BitField;
    So, if you want to store eight boolean numbers in just one byte, you can do that with a bit field. (Please correct me if I've misunderstood.)

    However, what's the point in using hex when defining? Is there any difference between writing:
    Code:
    #define CONSTANT 0x01
    // ... and ...
    #define CONSTANT 1
    I understand that it might be easier when the person reading it is internally converting it to binary, but what is (and I assume this exists) the reason(s) beyond that?

    I'd appreciate any help on this matter.

  2. #2
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Hex translates into decimal fine.

    It's just a way of assigning a value that humans can easily deconstruct into a binary string.

    Also, if you want 8 boolean numbers in one byte just use a char set a specific value.

    To set a bit,
    Code:
    unsigned i |= (1 << bit);
    To reset a bit,
    Code:
    unsigned i &= ~(1 << bit);
    You can just use the & operator to see if a particular bit is set.

  3. #3
    Registered User
    Join Date
    Jun 2011
    Posts
    4,508
    I'm personally not too keen on bit fields myself - I prefer packing information into a standard (unsigned) data type and using bitwise operators.

    Is there any difference between writing:

    Code:
    #define CONSTANT 0x01
    // ... and ...
    #define CONSTANT 1
    You might not see much of a difference there, since the numerical representations of decimal and hex are basically identical for values from zero to nine . But what about:

    Code:
    #define CONSTANT 0x1D
    // ... and ...
    #define CONSTANT 29
    It comes down to context. If you're using the values as actual numbers (such as defining the maximum size of an array), you'll want them to be in a decimal representation so that it's easy for you, the programmer, to easily understand the quantity.

    Hex values can be defined instead for several reasons. One is that, since it's a shorthand for binary, it's easier to define hex values used for masking.

    Code:
    #define ENABLE_MOTOR_1 0x08 // binary: 0000 1000
    #define ENABLE_MOTOR_2 0x02 // binary: 0000 0010
    
    // ...
    
    unsigned char control = 0x00;
    
    control |= ENABLE_MOTOR_1;     // control = 0x08, motor 1 on
    
    control |= ENABLE_MOTOR_2;     // control = 0x0A, motor 1 and motor 2 on
    
    control &= ~(ENABLE_MOTOR_1);  // control = 0x02, motor 2 on

  4. #4
    Registered User
    Join Date
    Sep 2014
    Posts
    26
    So, if I've understood it correctly, it can be used as follows:
    Code:
    // Base.h
    #define ENABLE_LIGHT 0x01   // 0000 0001
    #define ENABLE_ENGINE 0x02 // 0000 0010
    
    // Main.c
    unsigned char settings = 0x00;
    if (settings & (1 << CONSTANT_1)) { /* turn light on */ }
    if (settings & (1 << CONSTANT_2)) { /* turn engine on */ }

  5. #5
    Registered User
    Join Date
    Jun 2011
    Posts
    4,508
    Something like that, though I wouldn't use the bit shifts like that when you're defining specific hex values.

    I suggest you replace the "turn light on" and "turn engine on" comments with print messages and make a simple program that you can run and play with.

  6. #6
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    I would set settings to something non-zero but yeah, that's the gist of it.

  7. #7
    Registered User
    Join Date
    Sep 2014
    Posts
    26
    In that case, how would you enable, disable, toggle and check if a bit is enabled?

    I use this code:
    Code:
    #define EnableBit(var, pos) ((var) |= (1 << (pos - 1)))
    #define IsBitEnabled(var, pos) ((var) & (1 << (pos - 1)))
    
    int main()
    {
       EnableBit(settings, 2);
       printf("%d", IsBitEnabled(settings, 2));
    }
    But it shows "2" rather than "1" (it outputs the value of "settings" rather than true or false), which I had expected... What am I doing wrong?
    Last edited by MeNeedsHelp; 09-26-2014 at 10:59 AM.

  8. #8
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Quote Originally Posted by MeNeedsHelp View Post
    In that case, how would you enable, disable, toggle and check if a bit is enabled?
    You should in all honesty just google this.

  9. #9
    Registered User
    Join Date
    Sep 2014
    Posts
    26
    I assume you missed my edit, since it wasn't in the quote. My question was (initially, at least) poorly phrased.

  10. #10
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    I think 1 << (2 - 1) is equal to 2. Assuming var == 0, then you have 0010 which is 2. To get 1, use 1 << 0.

    Treat the bit position like you would with 2 ^ position. 1 == 2 ^ 0.

  11. #11
    Registered User
    Join Date
    Jun 2011
    Posts
    4,508
    It doesn't seem that strange when you work it out.

    Code:
    EnableBit(settings, 2);
       
    /* settings = 0x02; */
       
    IsBitEnabled(settings, 2)
    
    /*
       settings & (1 << (pos - 1))
       settings & (1 << (2-1))
       settings & (1 << 1)
       settings & 2
       0x02 & 0x02 = 0x02 = 2
    */
    Recall though, in C, true is not necessarily one - it's just non-zero. So if you used that macro in an "if()", it would work as expected.

    If you specifically wanted a 1 for true, you could always do something cute like:

    Code:
    #define IsBitEnabled(var, pos) (!!((var) & (1 << (pos - 1))))

  12. #12
    Registered User
    Join Date
    Sep 2014
    Posts
    26
    OK...

    Code:
    // Base.h
    #define LIGHT_ENABLED 0x01
    #define ENGINE_ENABLED 0x02
    #define RADIO_ENABLED 0x04
    #define AC_ENABLED 0x08
    
    #define EnableBit(var, pos) ((var) |= (1 << (pos - 1)))
    
    // Main.c
    
    EnableBit(settings, AC_ENABLED);
    "AC_ENABLED" equals eight, thus "EnableBit(settings, AC_ENABLED)" equals "var |= (1 << 8)" sets bit #8 rather than bit number four. How can I fix this apart from changing "RADIO_ENABLED" to 0x03 and "AC_ENABLED" to 0x04 (in which case, why would I even use hex?)?

  13. #13
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Why would you shift a bit 8 times when you really wanted to shift it only 4?

  14. #14
    Registered User
    Join Date
    Sep 2014
    Posts
    26
    0x01 = 0000 0001
    0x02 = 0000 0010
    0x04 = 0000 0100

    However,
    0x03 = 0000 0011

    If I just want to switch the bit four times, I would just set "RADIO_ENABLED" to 3 rather than 0x03. If I do it as shown above, I don't see any point in using hex.

    Sorry if I'm not making any sense here.

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,362
    Quote Originally Posted by MeNeedsHelp
    0x01 = 0000 0001
    0x02 = 0000 0010
    0x04 = 0000 0100

    However,
    0x03 = 0000 0011
    Indeed. Now consider a nibble of a byte in full:
    0x00 = 0000 0000
    0x01 = 0000 0001
    0x02 = 0000 0010
    0x04 = 0000 0100
    0x05 = 0000 0101
    0x06 = 0000 0110
    0x07 = 0000 0111
    0x08 = 0000 1000
    0x09 = 0000 1001
    0x0a = 0000 1010
    0x0b = 0000 1011
    0x0c = 0000 1100
    0x0d = 0000 1101
    0x0e = 0000 1110
    0x0f = 0000 1111

    Clearly, after the "0x" prefix, the "0" corresponds to one nibble and the other hex digit corresponds to the other nibble. If you are working with bitwise operations and have a mental map of hex digits to the corresponding nibble, you will be able to mentally identify the bits of any particular nibble more easily than if you were presented with the number in decimal representation (at least once the number is larger than 16).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bit-Fields in C.
    By Mr.Lnx in forum C Programming
    Replies: 5
    Last Post: 06-29-2014, 07:22 AM
  2. Bit fields
    By juice in forum C Programming
    Replies: 7
    Last Post: 12-13-2011, 08:38 AM
  3. Bit fields
    By Edelweiss in forum C Programming
    Replies: 5
    Last Post: 08-23-2011, 10:01 AM
  4. bit fields before non-bit fields . . .
    By dwks in forum C Programming
    Replies: 10
    Last Post: 10-13-2005, 02:36 AM
  5. Bit fields
    By GaPe in forum C Programming
    Replies: 8
    Last Post: 01-22-2002, 02:01 PM

Tags for this Thread