Public Group

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

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

## 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 on other sites
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 on other sites
If you're intent on combining char values that way, you should probably be working with unsigned chars.

##### Share on other sites
Quote:
 Original post by SiCraneIf 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 _fastcallDon'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 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 frubamMay 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 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 frubamMay 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 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 1111uint8_t g = 0x87 = 1000 0111uint8_t b = 0x12 = 0001 0010uint8_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] = 0xFFp[1] = 0xCCuint16_t* q = reinterpret_cast<uint16_t*>(p)uint16_t value = *q;

would also work.

Hope that helps!

##### Share on other sites
Quote:
 Original post by EskapadeIt 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 on other sites
Quote:
Original post by SiCrane
Quote:
 Original post by EskapadeIt 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 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;

1. 1
2. 2
3. 3
4. 4
Rutin
18
5. 5

• 12
• 9
• 12
• 37
• 12
• ### Forum Statistics

• Total Topics
631415
• Total Posts
2999964
×