Jump to content
  • Advertisement
Sign in to follow this  
frubam

getting an int from a char array after reading from a file

This topic is 3077 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'm trying to be able to expand a file from a particular game, so instead of manually hexing the data, I'd just make a program to do the work for me. I'm stuck where seekg() needs a int to jump to the position of the object's data offset. The data offset is represented as a 32-bit hex value, which its ASCII text chars are read from the file and placed into a char array. The data is definitely accurately represented in these arrays because I checked the values while debugging it. So I tried to write a function that takes the parameter of that char[4] array and convert it to a int value. However, i get some weird values when trying to display it and eventually, it crashes. Here's the code:

int charToInt(char file_data[])
{
//"file_data" is a 4-byte char array
cout << hex;
int val[4] = {0};
int total = NULL;

val[0] = int(file_data[0]);
std::cout <<"The value is " << val[0] << "\n\n";
val[1] = int(file_data[1]);
std::cout << "The value is " << val[1] << "\n\n";
val[2] = int(file_data[2]);
std::cout << "The value is " << val[2] << "\n\n";
val[3] = int(file_data[3]);
std::cout << "The value is " << val[3] << "\n\n";

total = (val[0] * 0xFFFFFF) + (val[1] * 0xFFFF)
+ (val[2] * 0xFF) + val[3];

std::cout << "\n\nThe total is " << total << " \n\n";
return total;
};


like for the first example, the 32-bit hex value should be 0x00000880, but the display shows that val[3] as 0xffffff80. I have no idea what I'm doing wrong =0(. Any guidance is appreciated m(_ _)m.

Share this post


Link to post
Share on other sites
Advertisement
Don't you mean:

total = (val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[1];

or

int total = *reinterpret_cast<int*>( &file_data[0] );

?

Also, remember that char and int are signed values, whose ranges are from -128 to 127 and -2147483647 to 2147483648. You can reinterpret_cast<unsigned char&>(file_data[0]) to the correct value.

Share this post


Link to post
Share on other sites
If you're intent on combining char values that way, you should probably be working with unsigned chars.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
If you're intent on combining char values that way, you should probably be working with unsigned chars.

Thanks, I'll do that.
Quote:
Original post by _fastcall
Don't you mean:

total = (val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[3];


May I ask what this does exactly? I don't think I've seen that syntax before.

I changed the ints to unsigned ints, but I still get that 0xffffffXX values for some reason and ends up crashing somewhere in mlock.c and dbgheap.c.

Share this post


Link to post
Share on other sites
The problem is here: (The main problem being as SiCrane said, if you plan on using data this way, file_data should be unsigned char in the first place.)
val[0] = int(file_data[0]);

If file_data[0] were "255" (-1 as represented by char), then val[0] becomes -1 (0xFFFFFFFF). However, if you were to work with unsigned char:
val[0] = int( reinterpret_cast<unsigned char&>(file_data[0]) );

If file_data[0] were "255" (255 as represented by unsigned char), then val[0] also becomes 255 (0x0000000FF).

Quote:
Original post by frubam
May I ask what this does exactly? I don't think I've seen that syntax before.


It's a series of bitwise operations that assemble four bytes into an integer; i.e. the array { 0x12, 0x23, 0x34, 0x45 } becomes 0x12233445.

Share this post


Link to post
Share on other sites
Quote:
Original post by _fastcall
The problem is here: (The main problem being as SiCrane said, if you plan on using data this way, file_data should be unsigned char in the first place.)
val[0] = int(file_data[0]);

If file_data[0] were "255" (-1 as represented by char), then val[0] becomes -1 (0xFFFFFFFF). However, if you were to work with unsigned char:
val[0] = int( reinterpret_cast<unsigned char&>(file_data[0]) );

If file_data[0] were "255" (255 as represented by unsigned char), then val[0] also becomes 255 (0x0000000FF).

Quote:
Original post by frubam
May I ask what this does exactly? I don't think I've seen that syntax before.


It's a series of bitwise operations that assemble four bytes into an integer; i.e. the array { 0x12, 0x23, 0x34, 0x45 } becomes 0x12233445.


Ah, I understand now, that's why it was showing up as 0xffffffxx. I vaguely remember going over bitwise ops in class =0\. Well anyway, it works perfectly. Thank you both m(_ _)m!!!

Share this post


Link to post
Share on other sites
It doesn't really matter whether you work with signed or unsigned here, to be honest. Still, it's good practice and if you're working with binary files you might want to include <stdint.h> to get data types of fixed size like uint8_t.

The binary operations works like this:
A uint8 (unsigned int, 8 bits = char on your platform, not necessarily others) consists of 8 Bits.
1000 0010 = 2^7 + 2^1 = 130.
You may also write this in hexadecimal: 1000 = 2^3 = 8 = 0x8, 0010 = 2^1 = 2 = 0x2. The two combined are written as 0x82. Because you can represent 8 Bits so easily this way, hexadecimal is used very often.

Now if you have a color RGBA, and each color channel (R, G, B, A respectively) consists of 8 Bits:

uint8_t r = 0xFF = 1111 1111
uint8_t g = 0x87 = 1000 0111
uint8_t b = 0x12 = 0001 0010
uint8_t a = 0xA3 = 1010 0011




and you want to represent a color in a 32 bit (4*8) integer, like you might know from HTML (#RRGGBBAA), you can do it like this:


uint32_t color = (a << 24) | (b << 16) | (g << 8) | r



The bit-operation g << 8 adds 8 0s to the right of g, for example:
g == 0x87 == 1000 0111
Therefore g << 8 == 0x8700 == 1000 0111 0000 0000.

If you now do (g << 8) | r, you get this (padded r with 0s at the front):

g << 8 == 0x8700 == 1000 0111 0000 0000
r == 0x00FF == 0000 0000 1111 1111

1000 0111 0000 0000
0000 0000 1111 1111 OR
-----------------
1000 0111 1111 1111 == 0x87FF

Repeat with blue and alpha.

I hope that sheds a light on this bitwise operation.


Note that you don't necessarily need to do this:

char* p = new uint8_t[2];
p[0] = 0xFF
p[1] = 0xCC

uint16_t* q = reinterpret_cast<uint16_t*>(p)
uint16_t value = *q;




would also work.

Hope that helps!

Share this post


Link to post
Share on other sites
Quote:
Original post by Eskapade
It doesn't really matter whether you work with signed or unsigned here, to be honest.

Run this program and see if the two lines produce the same result:

int main(int, char **) {
signed char a1 = 0x80;
signed char a2 = 0x80;

unsigned char b1 = 0x80;
unsigned char b2 = 0x80;

std::cout << std::hex;
std::cout << ((a1 << 8) | a2) << std::endl;
std::cout << ((b1 << 8) | b2) << std::endl;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Quote:
Original post by Eskapade
It doesn't really matter whether you work with signed or unsigned here, to be honest.

Run this program and see if the two lines produce the same result:

int main(int, char **) {
signed char a1 = 0x80;
signed char a2 = 0x80;

unsigned char b1 = 0x80;
unsigned char b2 = 0x80;

std::cout << std::hex;
std::cout << ((a1 << 8) | a2) << std::endl;
std::cout << ((b1 << 8) | b2) << std::endl;
}


Sorry for the misinformation, I forgot C/++ uses an arithmetic shift, not logical. Apologies :)

Share this post


Link to post
Share on other sites
What kind of shift C++ uses is irrelevant. The issue is that when you perform pretty much any operation on chars, including bitwise-or and shifts, the operands undergo integral promotion. Change the code to the following:

std::cout << (a1 | a2) << std::endl;
std::cout << (b1 | b2) << std::endl;

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!