DigitalZebra
DigitalZebra

Reputation: 41483

Store an int in a char array?

I want to store a 4-byte int in a char array... such that the first 4 locations of the char array are the 4 bytes of the int.

Then, I want to pull the int back out of the array...

Also, bonus points if someone can give me code for doing this in a loop... IE writing like 8 ints into a 32 byte array.

int har = 0x01010101;
char a[4];
int har2;

// write har into char such that:
// a[0] == 0x01, a[1] == 0x01, a[2] == 0x01, a[3] == 0x01 etc.....

// then, pull the bytes out of the array such that:
// har2 == har

Thanks guys!

EDIT: Assume int are 4 bytes...

EDIT2: Please don't care about endianness... I will be worrying about endianness. I just want different ways to acheive the above in C/C++. Thanks

EDIT3: If you can't tell, I'm trying to write a serialization class on the low level... so I'm looking for different strategies to serialize some common data types.

Upvotes: 26

Views: 74465

Answers (10)

pari
pari

Reputation: 195

char a[10];
int i=9;

a=boost::lexical_cast<char>(i)

found this is the best way to convert char into int and vice-versa.

alternative to boost::lexical_cast is sprintf.

char temp[5];
temp[0]="h"
temp[1]="e"
temp[2]="l"
temp[3]="l"
temp[5]='\0'
sprintf(temp+4,%d",9)
cout<<temp;

output would be :hell9

Upvotes: 1

Schlameel
Schlameel

Reputation: 413


    #include <stdint.h>

    int main(int argc, char* argv[]) {
        /* 8 ints in a loop */
        int i;
        int* intPtr
        int intArr[8] = {1, 2, 3, 4, 5, 6, 7, 8};
        char* charArr = malloc(32);

        for (i = 0; i < 8; i++) {
            intPtr = (int*) &(charArr[i * 4]);
          /*  ^            ^    ^        ^     */
          /* point at      |    |        |     */
          /*       cast as int* |        |     */
          /*               Address of    |     */
          /*            Location in char array */

            *intPtr = intArr[i]; /* write int at location pointed to */
        }

        /* Read ints out */
        for (i = 0; i < 8; i++) {
            intPtr = (int*) &(charArr[i * 4]);
            intArr[i] = *intPtr;
        }

        char* myArr = malloc(13);
        int myInt;
        uint8_t* p8;    /* unsigned 8-bit integer  */
        uint16_t* p16;  /* unsigned 16-bit integer */
        uint32_t* p32;  /* unsigned 32-bit integer */

        /* Using sizes other than 4-byte ints, */
        /* set all bits in myArr to 1          */
        p8 = (uint8_t*) &(myArr[0]);
        p16 = (uint16_t*) &(myArr[1]);
        p32 = (uint32_t*) &(myArr[5]);
        *p8 = 255;
        *p16 = 65535;
        *p32 = 4294967295;

        /* Get the values back out */
        p16 = (uint16_t*) &(myArr[1]);
        uint16_t my16 = *p16;

        /* Put the 16 bit int into a regular int */
        myInt = (int) my16;

    }

Upvotes: 2

codie
codie

Reputation: 1

union value {
   int i;
   char bytes[sizof(int)];
};

value v;
v.i = 2;

char* bytes = v.bytes;

Upvotes: 0

stonemetal
stonemetal

Reputation: 6208

Note: Accessing a union through an element that wasn't the last one assigned to is undefined behavior. (assuming a platform where characters are 8bits and ints are 4 bytes) A bit mask of 0xFF will mask off one character so

char arr[4];
int a = 5;

arr[3] = a & 0xff;
arr[2] = (a & 0xff00) >>8;
arr[1] = (a & 0xff0000) >>16;
arr[0] = (a & 0xff000000)>>24;

would make arr[0] hold the most significant byte and arr[3] hold the least.

edit:Just so you understand the trick & is bit wise 'and' where as && is logical 'and'. Thanks to the comments about the forgotten shift.

Upvotes: 9

Richard Corden
Richard Corden

Reputation: 21721

You can also use placement new for this:

void foo (int i) {
  char * c = new (&i) char[sizeof(i)];
}

Upvotes: 4

user184677
user184677

Reputation:

Not the most optimal way, but is endian safe.


int har = 0x01010101;
char a[4];
a[0] = har & 0xff;
a[1] = (har>>8)  & 0xff;
a[2] = (har>>16) & 0xff;
a[3] = (har>>24) & 0xff;

Upvotes: 25

GManNickG
GManNickG

Reputation: 503815

Don't use unions, Pavel clarifies:

It's U.B., because C++ prohibits accessing any union member other than the last one that was written to. In particular, the compiler is free to optimize away the assignment to int member out completely with the code above, since its value is not subsequently used (it only sees the subsequent read for the char[4] member, and has no obligation to provide any meaningful value there). In practice, g++ in particular is known for pulling such tricks, so this isn't just theory. On the other hand, using static_cast<void*> followed by static_cast<char*> is guaranteed to work.

– Pavel Minaev

Upvotes: 8

Ashwin
Ashwin

Reputation: 3637

int main() {
    typedef union foo {
        int x;
        char a[4];
    } foo;

    foo p;
    p.x = 0x01010101;
    printf("%x ", p.a[0]);
    printf("%x ", p.a[1]);
    printf("%x ", p.a[2]);
    printf("%x ", p.a[3]);

    return 0;
}

Bear in mind that the a[0] holds the LSB and a[3] holds the MSB, on a little endian machine.

Upvotes: 8

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118128

#include <stdio.h>

int main(void) {
    char a[sizeof(int)];
    *((int *) a) = 0x01010101;
    printf("%d\n", *((int *) a));
    return 0;
}

Keep in mind:

A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined.

Upvotes: 9

Pavel Minaev
Pavel Minaev

Reputation: 101565

Unless you care about byte order and such, memcpy will do the trick:

memcpy(a, &har, sizeof(har));
...
memcpy(&har2, a, sizeof(har2));

Of course, there's no guarantee that sizeof(int)==4 on any particular implementation (and there are real-world implementations for which this is in fact false).

Writing a loop should be trivial from here.

Upvotes: 42

Related Questions