20

I first convert an int32 number to char[4] array, then convert the array back to int32 by (int *), but the number isn't the same as before:

unsigned int num = 2130706432;
unsigned int x;
unsigned char a[4];

a[0] = (num>>24) & 0xFF;
a[1] = (num>>16) & 0xFF;
a[2] = (num>>8) & 0xFF;
a[3] = num & 0xFF;

x = *(int *)a;
printf("%d\n", x);

the output is 127. And if I set num = 127, the output is 2130706432. Does anyone have ideas?

Eric J.
  • 147,927
  • 63
  • 340
  • 553
stackunderflow
  • 877
  • 4
  • 13
  • 28
  • 7
    Is your platform little endian or big endian? http://en.wikipedia.org/wiki/Endianness The byte order for an int on your platform is probably not what you think it is. – Eric J. Nov 17 '11 at 19:26
  • @Eric J. oh i forgot this. Now it's solved, thank you – stackunderflow Nov 17 '11 at 19:30
  • @DavidHeffernan: it's tagged C. – ninjalj Nov 17 '11 at 19:33
  • 2
    @zwx: I think `x = *(int *)a;` violates strict-aliasing rules (try to compile with warnings enabled), in modern C you should use a union to do type-punning (but it's best to do it via bit-shifting). See http://stackoverflow.com/questions/8143857/bad-value-affectation-after-type-casting/8159802#8159802 – ninjalj Nov 17 '11 at 19:35
  • 3
    @ninjalj: Exactly. The code is actually UB. The correct way to go about this is to reverse the order: `unsigned int x; unsigned char * a = (unsigned char*)(&x);` – Kerrek SB Nov 17 '11 at 19:38
  • @ninjalj: Using unions for type punning is *also undefined behavior*. You can't safely read from an inactive member of the union. – Ben Voigt Dec 16 '13 at 18:58
  • @BenVoigt: In C99 it's not UB: http://stackoverflow.com/questions/8511676/portable-data-reinterpretation – ninjalj Dec 17 '13 at 12:44
  • Ahh, right, my earlier comment is based on the C++ rules. Sorry. (Although C did have such a rule, it was designated as a defect, as mentioned in the answers to the question @ninjalj linked) – Ben Voigt Dec 17 '13 at 14:59

4 Answers4

18

Reverse the order of the a[] indexes, e.g,. a[0] -> a[3]

I think you have the endianness in reverse.

Try this:

a[3] = (num>>24) & 0xFF;
a[2] = (num>>16) & 0xFF;
a[1] = (num>>8) & 0xFF;
a[0] = num & 0xFF;
Anthony Blake
  • 5,328
  • 2
  • 25
  • 24
10

To see what happens use

printf("%x\n", ...);

to print both input and output number.

Endian-independent way:

x = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
Adam Trhon
  • 2,915
  • 1
  • 20
  • 51
  • 1
    I don't know why this is voted up. As if it's an endian-independent way, it should work on my PC too. But I have to do quite the opposite `uint32_t var2 = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0];` – rightaway717 Dec 18 '14 at 16:33
  • 2
    I use `vector` and fill it with `uint32_t` vars using `memcpy`: `memcpy(&v[0], &var, sizeof var);` – rightaway717 Dec 19 '14 at 08:11
  • 1
    @rightaway717 So save it in endianess of your computer. To do it endian-independent way you have to convert uint32_t -> array as OP does and array -> uint32_t as I do. – Adam Trhon Dec 19 '14 at 14:15
6

This line is never going to work correctly on a little-endian machine:

x = *(int *)a;

You need to unpack the data before you print out the value.

Mike Steinert
  • 814
  • 5
  • 8
  • Additionally, it may not work on big-endian machines with compilers that take advantage of strict-aliasing rules. – ninjalj Nov 17 '11 at 19:39
5

Your code a[0] = (num>>24) & 0xFF; takes the most significant 8 bits from num and sticks them in the first byte of a. On little endian machines the first byte holds the least signficant bits. That means that on little endian machines, this code takes the most significant 8 bits and stores them in the place where the least significant bits go, changing the value.

2130706432 is 0x7F000000 in hex, and 127 is 0x0000007F.

Also, x = *(int *)a; results in undefined behavior. Consider hardware where reading an int from an improperly aligned address causes a bus error. If a doesn't happen to be aligned properly for an int then the program would crash.

A correct approach to interpreting the bytes as an int would be std::memcpy(&x, a, sizeof x);

bames53
  • 86,085
  • 15
  • 179
  • 244