shieldfoss
shieldfoss

Reputation: 884

Casting char * as int gives strange error

I've run into a slightly strange problem - I have a char array that I want to output as hex. I don't mind casting as int, but when I do, a lot of f's are added in front of some of the numbers. I have this code do my output for me:

for (int i = 0; i<(bmp.BytesPerRow*bmp.Height);i++) // once per color per pixel
{
    if(i%3==0) // one line between each pixel
    {
        cout << "\n";
    }

int tmp = (int) bmp.Raster[i];
cout << "\nbmp.Raster[" << i << "]": " << hex << tmp;

}

and my output looks like this:

bmp.Raster[0]: ffffffff
bmp.Raster[1]: ffffffff
bmp.Raster[2]: ffffffff

bmp.Raster[3]: 40
bmp.Raster[4]: 20
bmp.Raster[5]: ffffffe0

bmp.Raster[6]: 40
bmp.Raster[7]: ffffffe0
bmp.Raster[8]: 20
etc...

and frankly I don't get it. I could understand if it was

ff
ff
ff

40
20
e0

etc...

and I could understand if the f's were appended to everything (I'd figure it was an artifact of the casting process and just discard the first 6 outputs) but only to some? I don't get it.

Additional info:

bmp.Raster is from the class CRaster[1] kindly provided by Juan Soulie

IDE is Microsoft Visual C++ 2010 Express which automatically does #include "tchar.h", but I've tried commenting that library out and the oddity persists.

[1]http://www.cplusplus.com/files/winbmp.zip

EDIT: Some of you are providing suggestions for solutions - and I appreciate that - but mostly I'm asking here if somebody knows what the devil is going on?

EDIT AGAIN: Problem was resolved by James Kanze.

The loop has been changed to:

for (int i = 0; i<(bmp.BytesPerRow*bmp.Height);i++) // once per color per pixel
{
    if(i%3==0) // one line between each pixel
    {
        cout << "\n";
    }

uint8_t tmp0 = (uint8_t)bmp.Raster[i];
uint16_t tmp1 = (uint16_t)tmp0;
cout << "\nbmp.Raster[" << i << "]": " << hex << tmp1;

}

and the output is now correct.

Upvotes: 1

Views: 418

Answers (3)

James Kanze
James Kanze

Reputation: 153929

The problem is that plain char's on your machine are signed. (If you're not too concerned about portability, both g++ and VC++ have options to make plain char unsigned.) You need to first cast the char to unsigned char, then cast the unsigned char to int. Or, if you can change the data structures you're outputting, change them to use unsigned char; that seems more appropriate for things like bitmaps anyway.

Upvotes: 1

Mostafa
Mostafa

Reputation: 680

Use this line:

unsigned char tmp = bmp.Raster[i];

instead of:

int tmp = (int) bmp.Raster[i];

It might works.

Upvotes: 0

Pete Wilson
Pete Wilson

Reputation: 8694

Not this:

int tmp = (int) bmp.Raster[i];

but this:

int          tmp = (unsigned int) bmp.Raster[i];   // OR
unsigned int tmp =                bmp.Raster[i];

might work.

When you cast the byte value to a (signed) int, the sign bit (the high-order bit) of the byte gets propagated to fill the upper part of the integer. So a byte of (say) 0x80 becomes an int of something like 0xffffff80. Unsigned arithmetic yields the behavior you want.

Upvotes: 1

Related Questions