问题
i'm trying to read contents of PNG file.
As you may know, all data is written in a 4-byte manner in png files, both text and numbers. so if we have number 35234 it is save in this way: [1000][1001][1010][0010].
but sometimes numbers are shorter, so the first bytes are zero, and when I read the array and cast it from char* to integer I get wrong number. for example [0000] [0000] [0001] [1011] sometimes numbers are misinterpreted as negative numbers and simetimes as zero!
let me give you an intuitive example:
char s_num[4] = {120, 80, 40, 1};
int t_num = 0;
t_num = int(s_num);
I wish I could explain my problem well!
how can i cast such arrays into a single integer value?
ok ok ok, let me change my code to explain it better:
char s_num[4] = {0, 0, 0, 13};
int t_num;
t_num = *((int*) s_num);
cout << "t_num: " << t_num << endl;
here we have to get 13 as the result, ok? but again with this new solution the answer is wrong, you can test on your computers! i get this number:218103808 which is definitely wrong!
回答1:
You cast (char*) to (int). What you should do is cast to pointer to integer, i.e.
t_num = *((int*) s_num));
But really you should extract your code into it's own function and make sure that:
- endianness is correct
sizeof(int) == 4
- Use C++ casts (i.e.
static, dynamic, const, reinterpret
)
回答2:
Assuming a little-endian machine with a 32-bit integer, you can do:
char s_num[4] = {0xAF, 0x50, 0x28, 0x1};
int t_num = *((int*)s_num);
To break it into steps:
s_num
is an array, which can be interpreted as a pointer to its first element (char*
here)- Cast
s_num
toint*
because of (1) - it's OK to cast pointers - Access the integer pointed to by the cast pointer (dereference)
To have 0xAF
as the low byte of the integer. Fuller example (C code):
#include <stdio.h>
int main()
{
char s_num[4] = {0xAF, 0x50, 0x28, 0x1};
int t_num = *((int*)s_num);
printf("%x\n", t_num);
return 0;
}
Prints:
12850af
As expected.
Note that this method isn't too portable, as it assumes endianness and integer size. If you have a simple task to perform on a single machine you may get away with it, but for something production quality you'll have to take portability into account.
Also, in C++ code it would be better to use reinterpret_cast
instead of the C-style cast.
回答3:
I find using the std bitset the most explicit way of doing conversions (In particular debugging.)
The following perhaps is not what you want in your final code (too verbose maybe) - but I find it great for trying to understand exactly what is going on.
http://www.cplusplus.com/reference/stl/bitset/
#include <bitset>
#include <iostream>
#include <string>
int
main (int ac, char **av)
{
char s_num[4] = {120, 80, 40, 1};
std::bitset<8> zeroth = s_num[0];
std::bitset<8> first = s_num[1];
std::bitset<8> second = s_num[2];
std::bitset<8> third = s_num[3];
std::bitset<32> combo;
for(size_t i=0;i<8;++i){
combo[i] = zeroth[i];
combo[i+8] = first[i];
combo[i+16] = second[i];
combo[i+24] = third[i];
}
for(size_t i = 0; i<32; ++i)
{
std::cout<<"bits ["<<i<<"] ="<<combo.test(i)<<std::endl;
}
std::cout<<"int = "<<combo.to_ulong()<<std::endl;
}
回答4:
Axel's answer violates the strict aliasing rule, at least since C++14. So I post this answer for future users.
Apart from endianness and size issues, a safe way is to use std::memcpy, i.e.
unsigned char s_num[4] = {13, 0, 0, 0};
// ^^^^^^^^ // ^^ fix endianness issue
// use unsigned char to avoid potential issues caused by sign bit
int t_num;
std::memcpy(&t_num, s_num, 4);
回答5:
EDIT: it seems that you don't want to sum the numbers after all. Leaving this answer here for posterity, but it likely doesn't answer the question you want to ask.
You want to sum the values up, so use std::accumulate:
#include <numeric>
#include <iostream>
int main(void) {
char s_num[4] = {120,80,40,1};
std::cout << std::accumulate(s_num, s_num+4,0) << std::endl;
return 0;
}
Produces output:
pgp@axel02:~/tmp$ g++ -ansi -pedantic -W -Wall foo.cpp -ofoo
pgp@axel02:~/tmp$ ./foo
241
回答6:
Conversion is done good, because you aren't summing up these values but assign them as one value. If you want to sum them you have to do it manualy:
int i;
for (i = 0; i<4; ++i)
t_num += s_num[i];
回答7:
Did you know that int's in C++ overflow after the 32767'th value? That would explain your negative number for 35234.
The solution is to use a data type that can handle the larger values. See the Integer Overflow article for more information:
http://en.wikipedia.org/wiki/Integer_overflow
UPDATE: I wrote this not thinking that we all live in the modern world where 32 bit and 64 bit machines exist and flourish!! The overflow for int's is in fact much much larger than my original statement.
来源:https://stackoverflow.com/questions/4633252/how-to-cast-an-array-of-char-into-a-single-integer-number