如何将char数组转换为单个整数?

时间:2011-01-08 09:24:20

标签: c++ png integer char casting

我正在尝试阅读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这绝对是错的!

7 个答案:

答案 0 :(得分:12)

您将(char *)转换为(int)。你应该做的是转换为指向整数的指针,即

t_num = *((int*) s_num));

但实际上你应该将你的代码提取到它自己的函数中并确保:

  1. endianness是正确的
  2. sizeof(int) == 4
  3. 使用C ++强制转换(即static, dynamic, const, reinterpret

答案 1 :(得分:7)

假设一个具有32位整数的小端机器,你可以这样做:

char s_num[4] = {0xAF, 0x50, 0x28, 0x1};
int t_num = *((int*)s_num);

将其分解为步骤:

  1. s_num是一个数组,可以解释为指向其第一个元素的指针(此处为char*
  2. 因为(1)而将s_num投放到int* - 投射指针是可以的
  3. 访问转换指针所指向的整数(取消引用)
  4. 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的溢出实际上比我原来的声明大得多。