Peter Krejci
Peter Krejci

Reputation: 3192

Integer into char array

I need to convert integer value into char array on bit layer. Let's say int has 4 bytes and I need to split it into 4 chunks of length 1 byte as char array.

Example:

int a = 22445;
// this is in binary 00000000 00000000 1010111 10101101
...
//and the result I expect
char b[4];
b[0] = 0; //first chunk
b[1] = 0; //second chunk
b[2] = 87; //third chunk - in binary 1010111
b[3] = 173; //fourth chunk - 10101101

I need this conversion make really fast, if possible without any loops (some tricks with bit operations perhaps). The goal is thousands of such conversions in one second.

Upvotes: 1

Views: 3914

Answers (6)

neeKo
neeKo

Reputation: 4280

You have already accepted an answer, but I will still give mine, which might suit you better (or the same...). This is what I tested with:

int a[3] = {22445, 13, 1208132};

for (int i = 0; i < 3; i++)
{
    unsigned char * c = (unsigned char *)&a[i];
    cout << (unsigned int)c[0] << endl;
    cout << (unsigned int)c[1] << endl;

    cout << (unsigned int)c[2] << endl;
    cout << (unsigned int)c[3] << endl;
    cout << "---" << endl;
}

...and it works for me. Now I know you requested a char array, but this is equivalent. You also requested that c[0] == 0, c[1] == 0, c[2] == 87, c[3] == 173 for the first case, here the order is reversed.

Basically, you use the SAME value, you only access it differently.

Why haven't I used htonl(), you might ask?

Well since performance is an issue, I think you're better off not using it because it seems like a waste of (precious?) cycles to call a function which ensures that bytes will be in some order, when they could have been in that order already on some systems, and when you could have modified your code to use a different order if that was not the case.

So instead, you could have checked the order before, and then used different loops (more code, but improved performance) based on what the result of the test was.

Also, if you don't know if your system uses a 2 or 4 byte int, you could check that before, and again use different loops based on the result.

Point is: you will have more code, but you will not waste cycles in a critical area, which is inside the loop.

If you still have performance issues, you could unroll the loop (duplicate code inside the loop, and reduce loop counts) as this will also save you a couple of cycles.

Note that using c[0], c[1] etc.. is equivalent to *(c), *(c+1) as far as C++ is concerned.

Upvotes: 0

ruakh
ruakh

Reputation: 183544

I'm not sure if I recommend this, but you can #include <stddef.h> and <sys/types.h> and write:

*(u32_t *)b = htonl((u32_t)a);

(The htonl is to ensure that the integer is in big-endian order before you store it.)

Upvotes: 3

caf
caf

Reputation: 239331

Depending on how you want negative numbers represented, you can simply convert to unsigned and then use masks and shifts:

unsigned char b[4];
unsigned ua = a;

b[0] = (ua >> 24) & 0xff;
b[1] = (ua >> 16) & 0xff;
b[2] = (ua >> 8) & 0xff
b[3] = ua & 0xff;

(Due to the C rules for converting negative numbers to unsigned, this will produce the twos complement representation for negative numbers, which is almost certainly what you want).

Upvotes: 3

Kerrek SB
Kerrek SB

Reputation: 477504

To access the binary representation of any type, you can cast a pointer to a char-pointer:

T x;  // anything at all!

// In C++
unsigned char const * const p = reinterpret_cast<unsigned char const *>(&x);

/* In C */
unsigned char const * const p = (unsigned char const *)(&x);

// Example usage:
for (std::size_t i = 0; i != sizeof(T); ++i)
    std::printf("Byte %u is 0x%02X.\n", p[i]);

That is, you can treat p as the pointer to the first element of an array unsigned char[sizeof(T)]. (In your case, T = int.)

I used unsigned char here so that you don't get any sign extension problems when printing the binary value (e.g. through printf in my example). If you want to write the data to a file, you'd use char instead.

Upvotes: 1

Martin James
Martin James

Reputation: 24907

typedef union{
  byte intAsBytes[4];
  int int32;
}U_INTtoBYTE; 

Upvotes: -2

Matt
Matt

Reputation: 678

int a = 22445;
char *b = (char *)&a;
char b2 = *(b+2); // = 87
char b3 = *(b+3); // = 173

Upvotes: 3

Related Questions