4
votes

I'm trying to convert an unsigned char array buffer into a signed int (vice versa).

Below is a demo code:

int main(int argv, char* argc[])
{
    int original = 1054;
    unsigned int i = 1054;
    unsigned char c[4];
    int num;

    memcpy(c, (char*)&i, sizeof(int));

    //num  = *(int*) c;                          // method 1 get
    memcpy((char *)&num, c, sizeof(int));        // method 2 get
    printf("%d\n", num);

    return 0;
}

1) Which method should I use to get from unsigned char[] to int?

method 1 get or method 2 get? (or any suggestion)

2) How do I convert the int original into an unsigned char[]?

I need to send this integer via a buffer that only accepts unsigned char[]

Currently what i'm doing is converting the int to unsigned int then to char[], example :

int g = 1054;
unsigned char buf[4];
unsigned int n;
n = g;
memcpy(buf, (char*)&n, sizeof(int));

Although it works fine but i'm not sure if its the correct way or is it safe?

PS. I'm trying to send data between 2 devices via USB serial communication (between Raspberry Pi & Arduino)

2
Not sure if it's safe, but one thing to make it less unsafe is to say unsigned char buf[sizeof(int)] rather than unsigned char buf[4].user824425
method 1 may result in segfault if the char array is not properly alignedphuclv
num = *(int *)c don't do that, c is not required to be properly aligned for an intDavid Ranieri
Ok thanks for all suggestion! Shall stick to memcpy method!Doe Joe
*(int *)c also violates the strict aliasing rule, do not do thisM.M

2 Answers

4
votes

Below approach will work regardless of endianness on machines (assuming sizeof(int)==4):

unsigned char bytes[4];
unsigned int n = 45;

bytes[3] = (n >> 24) & 0xFF;
bytes[2] = (n >> 16) & 0xFF;
bytes[3] = (n >> 8) & 0xFF;
bytes[0] = n & 0xFF;

Above code converts integer to byte array in little endian way. Here is link also with more information.

For reverse operation, see the answers here.

The approach you have with memcpy may give different results on different computers. Because memcpy will copy whatever is there in source address to destionation, and depending if computer is little endian or big endian, there maybe a LSB or MSB at the starting source address.

3
votes

You could store both int (or unsigned int) and unsigned char array as union. This method is called type punning and it is fully sanitized by standard since C99 (it was common practice earlier, though). Assuming that sizeof(int) == 4:

#include <stdio.h>

union device_buffer {
    int i;
    unsigned char c[4];
};

int main(int argv, char* argc[])
{
    int original = 1054;

    union device_buffer db;
    db.i = original;

    for (int i = 0; i < 4; i++) {
        printf("c[i] = 0x%x\n", db.c[i]);
    }
}

Note that values in array are stored due to byte order, i.e. endianess.