Understanding bit shifting

https://www.youtube.com/watch?v=KjHKwCZyAhQ
So I am trying to get the same output this youtuber gets but I am stuck on part of his code. Namely, the bit shifting part. For example the width in the file header for a bmp file is 4 bytes for the format he is using, but the array is an unsigned char. Which can represent a max of 255, but I want create 640 pixels across.What I don't understand is how this code actually works...

1
2
3
4
5
6
int w=640;
 
 unsigned char bmpfileheader[14] = { 'B','M', 0,0,0,0, 0,0,0,0, 48,0,0,0 };

 bmpinfoheader[4] = (unsigned char)(w);
 bmpinfoheader[5] = (unsigned char)(w >> 8);


It looks like he is just taking the width,w, and multiplying it by 2^8. How is this helping me put 640 in an array that can only hold 255 in each unsigned char?! Also when I try to use cout to display bmpinfoheader[5] I get nonsense, but it is necessary to display the full size of the image!
Last edited on
Left-shift is multiplication.
Right-shift divides.

What if:
line 5 is like = w % 256
and
line 6 is like = w / 256;
>>8 shifts 8 bits, which is 1 byte. So a 2-byte integer 0xabcd becomes 0x00ab
which, as noted, is division by a power of 2 (because they are bits, it is always a power of 2, you can't use it for general division).

now, what this is really doing is serialization. Serialization is where you take data (of any type ... classes, doubles, arrays, complex<double>, doesn't matter) and brute force cast it into bytes to send it over a 'serial' connection (ethernet socket for example, in the old days a serial port, and serial ports are now USB where the S = serial...).

so in serialization you can take a 2 byte integer and jack it into 2 bytes one at a time in various ways. here, the author uses a dense brute force approach with convoluted bit logic to accomplish this: he takes the first byte of variable w and forces it into a byte, then he takes the second byte of w and shoves it into the next byte. Depending on the endian setup of your system, you can actually see this by hacking the code a little bit (thats a pun).

short * sp = (short*)(&(bmpinfoheader[4]));
cout << sp[0] << " " << w << endl; //should be the same, if the endian is matching. If not the bytes of w will be reversed and you will have to print them in hex (in that case abcd would be cdab and you can verify it that way visually).

and, the above code (again, endian..) gives you the actual true width. Or it should. w and sp[0] should be the width, in a 2 byte integer.

note that if endian matches you can just use sp[0] = w to accomplish what he did. If they don't match, you can do this to avoid the uglys:

sp = &w;
bmpinfoheader[4] = sp[1]; //reverse copy the bytes.
bmpinfoheader[5] = sp[0];

what he did works either way, of course, whereas the above only work on one integer format each. His way is more correct for portable code.
Last edited on
Topic archived. No new replies allowed.