how to cast an array of char into a single integer number?

你。 提交于 2019-12-18 13:28:20

问题


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:

  1. endianness is correct
  2. sizeof(int) == 4
  3. 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:

  1. s_num is an array, which can be interpreted as a pointer to its first element (char* here)
  2. Cast s_num to int* because of (1) - it's OK to cast pointers
  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!