BigBadWolf
BigBadWolf

Reputation: 603

C: Bitwise little-endian confusion

I am trying to read the header of a BMP file and extract the width from it. I know that the file format uses little-endian format, so I read it byte-per-byte, and wrote this function to assemble an integer from 4 chars/bytes:

int assembleInt(char pos1, char pos2, char pos3, char pos4)
{
  new_int = 0;
  new_int += (pos4 << 24);
  new_int += (pos3 << 16);
  new_int += (pos2 << 8);
  new_int += pos1;
  return new_int;
}

To me, this looks like it should work. If I read the width of a bitmap that is 1200*1200, I get 944. I have opened the file in a hex editor to check, and the file is okay.

I thought maybe it's because I'm trying to shift a char out of bounds, so I changed it to this:

int shifter = 0;
new_int += (shifter + pos4) << 24;

but it didn't solve anything. I hope you can help me, thanks a lot!

Upvotes: 2

Views: 399

Answers (2)

user555045
user555045

Reputation: 64913

The problem actually wasn't in the shifts, for the number 1200 something goes from in this line:

new_int += pos1;

There pos1 is implicitly converted to an int, and since it is a signed char with value 0xB0 (1200 = 0x4B0), it is interpreted as negative. That shows up as "1 less in the next byte".

The other lines have the same problem, but it is not expressed when the value 1200 is used. That made this problem particularly sneaky, since every intermediate value that you're likely to look at would be observed to be correct, while the wrong value is created in a line that looks like it couldn't be wrong. And in a way that line isn't really wrong, the types were wrong.

Upvotes: 1

Paul Ogilvie
Paul Ogilvie

Reputation: 25286

The BITMAPFILEHEADER does not have the width information. The BITMAPINFOHEADER has the width in the biWidth field, which is a 32 bit long of Intel-endianness (little-endian). The BITMAPINFOHEADER is at the beginning of the DIB, directly after the BITMAPFILEHEADER. You can access it as:

char *pDIB;  // the bitmap
width= ((LPBITMAPINFOHEADER)pDIB)->biWidth;

Upvotes: 1

Related Questions