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

27,098

Solution 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)

Solution 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.

Solution 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;
}

Solution 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);
Share:
27,098
sepisoad
Author by

sepisoad

My name is "Sepehr Aryani" and I'm A full-stack develper. I've been working professionally as a software engineer since 2010. My major area of interest is designing and developing services and web apps. I am proficient at C++/Go/Python/Javascript(React/Redux)

Updated on July 22, 2022

Comments

  • sepisoad
    sepisoad almost 2 years

    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!

  • Eli Bendersky
    Eli Bendersky over 13 years
    What machine do you have that overflows an int on 32767?
  • Philip Potter
    Philip Potter over 13 years
    not necessarily so. Many C++ implementations have 32-bit or even 64-bit int which won't overflow after 32767.
  • Eli Bendersky
    Eli Bendersky over 13 years
    @Philip: "Many..." is putting it mildly. It would be challenging to find one where it's smaller than 32 bits these days, outside of the embedded domain of course.
  • Eli Bendersky
    Eli Bendersky over 13 years
    I'm not sure this is what he's asking
  • Philip Potter
    Philip Potter over 13 years
    @Eli i don't think he's sure what he's asking. But this is the result that his example asks for.
  • jamesmortensen
    jamesmortensen over 13 years
    I stand corrected. I must have been dyslexic and looking at the wrong data type. With that said, do we need to remove this answer?
  • Axel
    Axel over 13 years
    haha, so there's someone still stuck on a 16-bit compiler. embedded system?
  • sepisoad
    sepisoad over 13 years
    the same happend when I used your solution
  • Axel
    Axel over 13 years
    what does same results mean? perhaps you should explain, why you expect this to give 241...
  • Axel
    Axel over 13 years
    Oh... what you want is just to sum up the byte values of your 4 characters. That would give 241. Macieks' answer does that. But is that really what you want to do? Looks strange to me (not the code, I'm trying to understand your problem).
  • AndyG
    AndyG over 7 years
    @iammilind: Did you read the entirety of the answer you linked? char* is one of the few occasions where this doesn't break aliasing
  • AndyG
    AndyG over 7 years
    @iammilind: To back up my statement, refer to the C++ standard §3.10/10 Lvalues and rvalues [basic.lval] Which makes special provisions for char and unsigned char
  • xskxzr
    xskxzr over 6 years
  • Summer Sun
    Summer Sun almost 6 years
    could you explain why is it of reverse order, I think it should be af50281?
  • Summer Sun
    Summer Sun almost 6 years
    Thank you Eli, I got it now.