I'm pretty sure its just a matter of some bitwise operations, I'm just not entirely sure of exactly what I should be doing, and all searches return back "64 bit vs 32 bit".
8 Answers
pack:
u32 x, y;
u64 v = ((u64)x) << 32 | y;
unpack:
x = (u32)((v & 0xFFFFFFFF00000000LL) >> 32);
y = (u32)(v & 0xFFFFFFFFLL);

- 131,802
- 30
- 241
- 343
-
39You don't need the explicit bitmasks when unpacking; `x = (u32)(v>>32); y = (u32)v;` does the job. – Mike Seymour May 11 '10 at 13:26
-
@MikeSeymour or Jack - Is it easy for you to find in the C++11 standard confirmation that this is guaranteed to work for all compliant compilers? – Dan Nissenbaum Apr 21 '14 at 00:19
-
1@DanNissenbaum: Shift operators are specified in 5.8 - well defined for all unsigned values if the shift is in range, as it is here. Unsigned integral conversions are specified in 4.7/2 - defined to preserve all the bits that fit in the new type (specified in terms of modular arithmetic). – Mike Seymour Apr 21 '14 at 10:47
Or this, if you're not interested in what the two 32-bits numbers mean:
u32 x[2];
u64 z;
memcpy(x,&z,sizeof(z));
memcpy(&z,x,sizeof(z));

- 70,581
- 9
- 108
- 149
-
1+1 for not introducing types and bitshifts. I'd prefer assignments over `memcpy` though. – Michael Krelin - hacker May 11 '10 at 12:03
-
2Goz, it's not about performance, it's about my (my!) perception of code beauty. – Michael Krelin - hacker May 11 '10 at 12:41
-
1Be wary that some hardware is big endian and some hardware is little endian – James Wierzba Oct 27 '18 at 00:45
Use a union and get rid of the bit-operations:
<stdint.h> // for int32_t, int64_t
union {
int64_t big;
struct {
int32_t x;
int32_t y;
};
};
assert(&y == &x + sizeof(x));
simple as that. big consists of both x and y.

- 12,825
- 5
- 58
- 90
-
2+1 for the union, but it would be better to use standard fixed size types from `
`, i.e. `int32_t`, `int64_t`, since sizeof(long) and sizeof(long long) are not guaranteed to be any particular value. – Paul R May 11 '10 at 12:13 -
What is an aliasing error? What should be avoided at all costs? The real problem I see here is that you can't guarantee `y` is not aligned away without taking extra measures. – Michael Krelin - hacker May 11 '10 at 12:43
-
2My mistake it leads to undefined behaviour. According to the spec, if you write to big you can't assume that x and y contain anything. The only member of the union that contains valid data is big. Most compilers DO support it but it IS undefined behaviour. You really are better off using a fixed size memcpy that any optimiser worth its salt will optimise out anyway. – Goz May 11 '10 at 13:02
-
Well, you can't assume anything according to specs, because there's no anonymous structs in there ;-) So the statement about big being the only member containing data makes about as little sense. But it's not undefined behavior - it should be either compile error or working. And I'm yet to see the compiler that goes beyond warning user against it (I do believe such a compiler exists, of course). – Michael Krelin - hacker May 11 '10 at 13:23
-
Viktor, not that it matters, but why do you add sizeof(*y*) to the address of x? ;-) – Michael Krelin - hacker May 11 '10 at 13:24
-
@Goz: because of the anonymous struct?, or cant you guaranteed anything with union? – Viktor Sehr May 11 '10 at 13:54
-
1@Viktor: You can ONLY guarantee that the element you just wrote in is valid. ie if you do myUnion.big = 64; then the only defined way to get the value again is by looking at myUnion.big. Anything else is undefined. – Goz May 11 '10 at 13:57
-
Actually, you're guaranteed to have syntax error, because there's no semicolon after struct ;-) Goz, you're confusing the hell out of everyone. Anonymous structs are indeed not standardized, but what the hell do you mean by being undefined? How can it be undefined if compiler accepts it? Can it possibly put another union member elsewhere? – Michael Krelin - hacker May 11 '10 at 19:48
-
@Goz: could you give a usage example where the behavious is undefined? is the struct (could be replaced by an array[2]) or the union the problem= – Viktor Sehr May 11 '10 at 20:46
-
Turning struct into array should please both Goz and standards and also rule out the possibility alignment troubles. – Michael Krelin - hacker May 12 '10 at 06:55
-
1@Everyone: Regardless of the anonymous-ness of any of those options if you write a value into big then the only defined way to get that value is through big. Using another entry in the union is undefined behaviour. It works on most compilers I totally agree but it is still undefined behaviour. – Goz May 12 '10 at 08:46
-
@Goz: but is it undefined to assign values to x and y, pass big around as an int64, and extract x any back via a union? I can't see which operation is undefined? – Viktor Sehr May 12 '10 at 08:59
-
Goz, now I see your point. Union guarantees that all of its members start at the same memory location. Which means, having `union { uint32_t big; uint16_t smalls[2]; uint8_t smallers[4]; };` yields perfectly defined (though architecture-dependent) behaviour. – Michael Krelin - hacker May 12 '10 at 10:30
-
-
1@Everyone except Goz: http://stackoverflow.com/questions/10271929/union-for-uint32-t-and-uint8-t4-undefined-behavior – Mooing Duck Oct 17 '12 at 16:18
-
2This should be voted as the answer. Bit shifting operations assume a specific storage order of 64 bit numbers (big-endian/little-endian) and therefor inherently not portable. I assume the compiler will treat the union in the order supported by the underlying hardware/os. – theking2 Mar 03 '21 at 11:25
-
@theking2 No, the bit shifts are defined to produce a specific arithmetic value, which is then stored however the implementation stores values. It is totally portable. You only have to care about endianness if you are inspecting the bytes that a particular implementation uses – Caleth May 10 '23 at 08:55
I don't know if this is any better than the union or memcpy solutions, but I had to unpack/pack signed 64bit integers and didn't really want to mask or shift anything, so I ended up simply treating the 64bit value as two 32bit values and assign them directly like so:
#include <stdio.h>
#include <stdint.h>
void repack(int64_t in)
{
int32_t a, b;
printf("input: %016llx\n", (long long int) in);
a = ((int32_t *) &in)[0];
b = ((int32_t *) &in)[1];
printf("unpacked: %08x %08x\n", b, a);
((int32_t *) &in)[0] = a;
((int32_t *) &in)[1] = b;
printf("repacked: %016llx\n\n", (long long int) in);
}

- 2,815
- 3
- 19
- 12
The basic method is as follows:
uint64_t int64;
uint32_t int32_1, int32_2;
int32_1 = int64 & 0xFFFFFFFF;
int32_2 = (int64 & (0xFFFFFFFF << 32) ) >> 32;
// ...
int64 = int32_1 | (int32_2 << 32);
Note that your integers must be unsigned; or the operations are undefined.

- 28,471
- 6
- 52
- 68
As a summary from Mike and Jack, without using C-style casting:
Variables:
int64_t combined;
int32_t upper,lower;
int64_t->int32_t
upper = static_cast<int32_t>(combined >> 32);
lower = static_cast<int32_t>(combined);
int32_t->int64_t
combined = (static_cast<int64_t>(upper)) << 32 | lower;

- 107
- 1
- 5
long x = 0xFEDCBA9876543210;
cout << hex << "0x" << x << endl;
int a = x ;
cout << hex << "0x" << a << endl;
int b = (x >> 32);
cout << hex << "0x" << b << endl;

- 11
- 3
-
1While this code snippet may be the solution, [including an explanation](//meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – HMD Dec 25 '18 at 10:35
Not sure if this way of doing is good for portability or others but I use...
#include <stdio.h>
#include <stdint.h>
typedef enum {false, true} bool;
#ifndef UINT32_WIDTH
#define UINT32_WIDTH 32 // defined in stdint.h, but compiler error ??
#endif
typedef struct{
struct{ // anonymous struct
uint32_t x;
uint32_t y;
};}ts_point;
typedef struct{
struct{ // anonymous struct
uint32_t line;
uint32_t column;
};}ts_position;
bool is_little_endian()
{
uint8_t n = 1;
return *(char *)&n == 1;
}
int main(void)
{
uint32_t x, y;
uint64_t packed;
ts_point *point; // struct offers a "mask" to retreive data
ts_position *position; // in an ordered and comprehensive way.
x = -12;
y = -23;
printf("at start: x = %i | y = %i\n", x, y);
if (is_little_endian()){
packed = (uint64_t)y << UINT32_WIDTH | (uint64_t)x;
}else{
packed = (uint64_t)x << UINT32_WIDTH | (uint64_t)y;
}
printf("packed: position = %llu\n", packed);
point = (ts_point*)&packed;
printf("unpacked: x = %i | y = %i\n", point->x, point->y); // access via pointer
position = (ts_position*)&packed;
printf("unpacked: line = %i | column = %i\n", position->line, position->column);
return 0;
}
I like the way I do as it's offer lots of readiness and can be applied in manay ways ie. 02x32, 04x16, 08x08, etc. I'm new at C so feel free to critic my code and way of doing... thanks

- 31
- 6