Jump to content
  • Advertisement
Sign in to follow this  
fpsgamer

[C++] Error after type conversion from unsigned char* to char*

This topic is 3657 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a program that parses binary data. I experienced a problem with code similar to the following:
/*1) This works fine:*/
unsigned char buffer[] = {0x00, 0x00, 0x01, 0xb3};
assert(buffer[0] == 0x00);
assert(buffer[1] == 0x00);
assert(buffer[2] == 0x01);
assert(buffer[3] == 0xb3);


/*2) This fails:*/
unsigned char buffer[] = {0x00, 0x00, 0x01, 0xb3};
char* buf = (char*)buffer; /* Interpret the buffer as char* instead */
assert(buf[0] == 0x00);
assert(buf[1] == 0x00);
assert(buf[2] == 0x01);
assert(buf[3] == 0xb3); /* Assertion FAILED! */


I suspect the reason why #1 succeeds and #2 fails has something to do with subtle type conversions. Could someone help me trace out exactly what is happening, and perhaps suggest how I should properly avoid this pitfall. On a related note, when doing byte or bit level parsing, by convention what type should the buffer be? char*, unsigned char*, uint8_t*, int8_t* etc?

Share this post


Link to post
Share on other sites
Advertisement
If char happens to be a signed type then it is no wonder that a negative value is not equal to 0xb3. (My compiler emits a warning that the comparison will always be false due to limited range of data.)

Share this post


Link to post
Share on other sites
buf[3] is of type char, 0xb3 is of type int. In order to compare these two, the compiler has to convert the char to an int, and 0xffffffb3 is not equal to 0xb3.
char c = 0xb3;
if (c != 0xb3) cout << "Whoops..." << endl;


For these situations, I recommend
typedef unsigned char byte;

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
buf[3] is of type char, 0xb3 is of type int. In order to compare these two, the compiler has to convert the char to an int, and 0xffffffb3 is not equal to 0xb3.
char c = 0xb3;
if (c != 0xb3) cout << "Whoops..." << endl;


For these situations, I recommend
typedef unsigned char byte;


Okay I think I get it:

The key is that all unqualified integral constants are signed integers. :)

Conversion from signed int -> unsigned char -> signed int

unsigned char a = 0xb3; // '0000 0000 1011 0011' -> '1011 0011'
int b = a; // '1011 0011' -> '0000 0000 1011 0011'
assert(b == 0xb3); // OK!








Conversion from signed int -> signed char -> signed int

/* Truncates MSB due to 2's compliment precision */
char a = 0xb3 // '0000 0000 1011 0011' -> 'X011 0011'
int b = a; // '0011 0011' -> '0000 0000 0011 0011'
assert(b == 0xb3); // ERROR! '0000 0000 1011 0011' != '0000 0000 0011 0011'








So is the moral of the story always to use 'unsigned char' when parsing binary data? Also would this be a case where heavy use of a uin8_t typdef would be warranted?

Share this post


Link to post
Share on other sites
I was beaten to the punch, but since I'm already finished with this example code, here it is.
Also I recommend this wikipedia article if you want to know all the gory details behind what's going on.


#include <iostream>

template <class T>
void print_bits(T obj) {
int c = sizeof(obj);
unsigned char * bytes = (unsigned char *)&obj; //& means address of
for(int i = 0; i < c; ++i) //iterate over bytes
for(int j = (sizeof(unsigned char)*8); j >= 0; --j)//iterate over bits
std::cout << ((bytes >> j) & 1);
std::cout << "\n";
}

int main(int argc, char ** argv) {
unsigned char buffer1[] = {0x00, 0x00, 0x01, 0xb3, 0x7f, 0x80, 0xff};
char* buffer2 = (char*)buffer1;

for(int i = 0; i < 7; ++i)
std::cout << i+1 <<"\t1: "<<(int)buffer1<<"\t2: "<<(int)buffer2<<"\n";
std::cout << "\n";

std::cout << "Unsigned\n4\t1:\t";
print_bits<unsigned char>(buffer1[3]);
std::cout << "4\t2:\t";
print_bits<unsigned char>(buffer2[3]);

std::cout << "Signed\n4\t1:\t";
print_bits<char>(buffer1[3]);
std::cout << "4\t2:\t";
print_bits<char>(buffer2[3]);

return 0;
}




EDIT:
Maybe not always but I do like to read and write binary data in unsigned bytes in general.
But if you want to store a signed char to a (1-byte) binary file, you'd want to read it back in as a signed char also.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!