Skip to main content
gamedev.net
🔒 Locked

Bits, Bytes, and Bitwise Operators

Started by openglJunkie 10 replies 2.1k views
Original Post
openglJunkie
openglJunkie
Hello, I'm trying to understand bits and bytes and hex more. I found the wikipedia page for bitwise operators which helped, although, I still don't understand enough about bits and bytes. I understand bits are binary digits ( 0 and 1 ) and hexadecimal is 0-F to represent 0 to 16, but when I try to code anything that uses either one of these I'm confused. I'm currently studying a BMP image loader, which converts to the correct Endian form and I'm trying to see what is happening as I'm reading the code. It's cool that someone has already written some code to do this, but if I don't understand why it's doing it, that's not going to help me as a developer at all.
Nich
Nich
This might not completely answer your question, but I'll try my best.

A bit is a single binary digit, and a byte is a group of 8 bits. One byte can represent up to the number 255.

You convert Binary to Hex by taking groups of four bits at a time. You'll note that you can represent up to the number 15 with four binary digits. 0000 is 0, 1111 is F = 15, 1010 is A = 10, etc.

But you'll recall that a byte is 8, and not 4 bits, so you need to use two. The number FF in hex is 255

Typical RBG form uses one byte for each color, so you have 0xRRGGBB

Once you know all this, it's easier to see what happens when you perform an operation such as 16 & 48 (and). 16 converts to 10 in hex, which is 0001 0000 in binary, while 48 converts to 30 in hex, which is 0011 0000 in binary. Then you compare each digit, and if they are the same, you put a 1 in that space, otherwise you put a 0. The answer is 0001 0000 in binary = 10 in hex = 16 in decimal. Each operation will compare the bits differently, but essentially they are the same.

The shift operations simply move the bits to the left or right, and fill in the extra space with 0's. 50 is 32 in hex, which is 0011 0010 in binary. 50 << 2 is 1100 1000, which is C8 in hex, or 200 in binary. Right shift just works the other way around.

For working with colors, since they're stored in a 6 byte format, you can add a byte to affect the blue hue, add a byte shifted by 8 to access affect the green hue, and add a byte shifted by 16 to access the red hue. For example, if you have a color stored in a variable col, you could add 10 to the red hue by saying

col += 10 << 16;

I hope that helps.
Calexus
Calexus
Maybe its just me having problem reading between the lines but if you already understand the bitwise operations then what is your problem?

There isn't really any connection between bin and hex, numbers are numbers no matter what base you write them in.

One useful thing to notice is that you need 4 bits to write a hex number, that is 0xF = 1111b = 15 decimal.

0x0= 0 in decimal and 0000 in binary
...
0x7= 7 in decimal and 0111 in binary
...
0xA= 10 in decimal and 1010 in binary
0xB= 11 in decimal and 1011 in binary
...

You write an 8 bit number with two hex numbers ex. 0xFF is 255dec and 11111111b

And you write a 16 bit number with 4 etc. 0xFF0A is 65290dec and 1111111100001010b

If you want to print in binary you have to do it yourself using something like this:
unsigned char mask= 1 << 7; //Put a "one" in bit 7, that is 0000 0001 << 7 == 1000 0000while(mask)//While not 0{   cout << (var & mask ? '1' : '0'); //Print 1 or 0, 1 if the "high" bit in the mask is high in var and 0 if its not   mask >>= 1;//Shift the mask one bit to the right to print the next bit, 1000 0000 >> 1 == 0100 0000                      }


[Edited by - Calexus on January 1, 2009 4:18:53 PM]
Exitus Acta Probat
openglJunkie
openglJunkie
Both of those helped find the missing link. I hadn't realized it took 4 bytes to represent a hex (that may be why I couldn't convert between the two) or how it was used to represent colors. There's one thing I didn't understand, though:

Quote:

You write an 8 bit number with two hex numbers ex. 0xFF is 255dec and 11111111b


Why did you include the letter 'b' at the end of the binary notation? I never understood what the purpose of the '0X...' accomplished in representing hex. I read that this was the C++ way of representing hex, but it never explained why.
mumpo
mumpo
Quote:
Original post by openglJunkie
Why did you include the letter 'b' at the end of the binary notation? I never understood what the purpose of the '0X...' accomplished in representing hex. I read that this was the C++ way of representing hex, but it never explained why.


The 0x prefix tells you the number is in hexadecimal. The b postfix tells you the number is in binary. Why is this important? Because a sequence of digits which represents a valid binary number, such as 10, could also represent a different decimal or hexadecimal number:

10 (binary) == 2 (decimal)
10 (decimal) == 10 (decimal)
10 (hexadecimal) == 16 (decimal)

In the same way, a number that happened to use only digits 0-9 in hexadecimal could be mistaken for decimal:

25 (decimal) == 25 (decimal)
25 (hexadecimal) == 37 (decimal)

Hence we write

10b == 2
10 == 10
0x10 == 16
25 == 25
0x25 == 37
Calexus
Calexus
Quote:
Why did you include the letter 'b' at the end of the binary notation? I never understood what the purpose of the '0X...' accomplished in representing hex. I read that this was the C++ way of representing hex, but it never explained why.


Thats right, you write an hex number as 0x... in c/c++/whatever and an number starting with a zero would be an octal number (8 digits, 0-7). And a number starting with, well not 0 or 0x is a decimal number. The "b" at the end is just way of saying that its binary, its not standard but its a pretty common way of showing that its binary.

Do note that you cant write numbers as binary in c++ (and other), you have to write them in dec/hex/oct. Hex is probably the most common way as you have the one hex digit = 4 bits (1 nibble) thingie which makes it a bit easier.

   DEC   HEX      BIN      OCT-----------------------------------------------   0  |  0x0   |  0000  |  00   1  |  0x1   |  0001  |  01   2  |  0x2   |  0010  |  02   3  |  0x3   |  0011  |  03   4  |  0x4   |  0100  |  04   5  |  0x5   |  0101  |  05   6  |  0x6   |  0110  |  06   7  |  0x7   |  0111  |  07   8  |  0x8   |  1000  |  010   9  |  0x9   |  1001  |  011   10 |  0xA   |  1010  |  012   11 |  0xB   |  1011  |  013   12 |  0xC   |  1100  |  014   13 |  0xD   |  1101  |  015   14 |  0xE   |  1110  |  016   15 |  0xF   |  1111  |  017-----------------------------------------------
Exitus Acta Probat
owiley
owiley
closest thing to binary in c++ would be the bool data type its either true==1 or false==0 yeah but using hex and just plain decimal format is suffient
Bring more Pain
the_edd
the_edd
Quote:
Original post by owiley
closest thing to binary in c++ would be the bool data type its either true==1 or false==0 yeah but using hex and just plain decimal format is suffient


There's a common meta-programming trick for binary "literals":

#include <iostream>template<unsigned long digits>struct binary{    static const unsigned long value = (digits % 2) + 2 * binary<digits / 10>::value;};template<>struct binary<0>{    static const unsigned long value = 0;};int main(){    std::cout << binary<1100101>::value << '\n';    return 0;}
openglJunkie
openglJunkie
Ok, I'm starting to become familar with it now. Here's a notation used by OpenGL for their lights:

GL_LIGHT0 = 0x4000
GL_LIGHT1 = 0x4001
...

Was the purpose of having it in this format to be similar to a nibble, 4 bits?

[Edited by - openglJunkie on January 1, 2009 8:00:38 PM]
Nypyren
Nypyren
Quote:
Original post by openglJunkie
...I hadn't realized it took 4 bytes to represent a hex...


bit = either 0 or 1.
nibble = 4 bits, representing 16 combinations.
byte = 8 bits, representing 256 combinations.

"hex" is not an AMOUNT of bits, it is a way to write those bits in a different form.

One digit in hexadecimal FORM has 16 combinations, so a single hexadecimal digit represents one nibble.
Nypyren
Nypyren
Quote:
Original post by openglJunkie
Ok, I'm starting to become familar with it now. Here's a notation used by OpenGL for their lights:

GL_LIGHT0 = 0x4000
GL_LIGHT1 = 0x4001
...

Was the purpose of having it in this format to be similar to a nibble, 4 bits?


Those are 16-bit values (4 hexadecimal digits x 4 bits per digit = 16).

I don't use GL, but it seems like they are using the high bits to indicate the feature (a light) and the lower bits to indicate its ID. It's something that is either meant for internal use only, or has some documention somewhere that explains their constant format.

Sometimes constant IDs like this are spaced out (for example, lights at 0x4000, and the next group at 0x4100) and aren't used as a bitfield at all - they leave extra space in the ID list in case they add more lights at some point in the future.
iMalc
iMalc
Quote:
Original post by Nich
The shift operations simply move the bits to the left or right, and fill in the extra space with 0's. 50 is 32 in hex, which is 0011 0010 in binary. 50 << 2 is 1100 1000, which is C8 in hex, or 200 in binary. Right shift just works the other way around.
Ahem!
200 in decimal[smile]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.