我正在尝试阅读PNG文件的内容。
如您所知,所有数据都以4字节方式写入png文件,包括文本和数字。所以,如果我们有号码35234,就会以这种方式保存: [1000] [1001] [1010] [0010]。
但有时数字较短,所以第一个字节为零,当我读取数组并将其从char *转换为整数时,我得到错误的数字。例如[0000] [0001] [1011] 有时数字被误解为负数,而simetimes被误解为零!
让我给你一个直观的例子:
char s_num[4] = {120, 80, 40, 1};
int t_num = 0;
t_num = int(s_num);
我希望我能很好地解释我的问题!
如何将这些数组转换为单个整数值?
好的好的,让我更改我的代码以更好地解释它:
char s_num[4] = {0, 0, 0, 13};
int t_num;
t_num = *((int*) s_num);
cout << "t_num: " << t_num << endl;
在这里我们必须得到13作为结果,好吗? 但是再次使用这个新解决方案,答案是错误的,您可以在您的计算机上进行测试! 我得到这个号码:218103808这绝对是错的!
答案 0 :(得分:12)
您将(char *)转换为(int)。你应该做的是转换为指向整数的指针,即
t_num = *((int*) s_num));
但实际上你应该将你的代码提取到它自己的函数中并确保:
sizeof(int) == 4
static, dynamic, const, reinterpret
)答案 1 :(得分:7)
假设一个具有32位整数的小端机器,你可以这样做:
char s_num[4] = {0xAF, 0x50, 0x28, 0x1};
int t_num = *((int*)s_num);
将其分解为步骤:
s_num
是一个数组,可以解释为指向其第一个元素的指针(此处为char*
)s_num
投放到int*
- 投射指针是可以的将0xAF
作为整数的低字节。富勒示例(C代码):
#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;
}
打印:
12850af
正如所料。
请注意,此方法不太可移植,因为它假定字节顺序和整数大小。如果你有一个简单的任务要在一台机器上执行,你可能会侥幸逃脱它,但对于生产质量,你必须考虑到可移植性。
此外,在C ++代码中,最好使用reinterpret_cast
而不是C风格的转换。
答案 2 :(得分:2)
我发现使用std bitset进行转换的最明确方式(特别是调试。)
以下可能不是你想要的最终代码(可能过于冗长) - 但我发现它非常适合于准确理解发生了什么。
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;
}
答案 3 :(得分:1)
Axel的回答violates the strict aliasing rule,至少从C ++开始14。所以我将这个答案发布给未来的用户。
除了字节序和大小问题外,一种安全的方法是使用std::memcpy
,即
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);
答案 4 :(得分:0)
转换效果很好,因为您没有总结这些值,而是将它们指定为一个值。如果你想总结它们,你必须手工制作:
int i;
for (i = 0; i<4; ++i)
t_num += s_num[i];
答案 5 :(得分:0)
您想要对值进行求和,因此请使用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;
}
产生输出:
pgp@axel02:~/tmp$ g++ -ansi -pedantic -W -Wall foo.cpp -ofoo
pgp@axel02:~/tmp$ ./foo
241
答案 6 :(得分:-1)
您是否知道在32767'值之后C ++中的int溢出?这可以解释你的35234的负数。
解决方案是使用可以处理更大值的数据类型。有关更多信息,请参阅Integer Overflow文章:
http://en.wikipedia.org/wiki/Integer_overflow
更新:我写的并不认为我们都生活在32位和64位机器存在且蓬勃发展的现代世界中! int的溢出实际上比我原来的声明大得多。