tags:

views:

301

answers:

4

Hi, basically exactly as the title says, 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" etc etc thanks

+8  A: 

pack:

u32 x, y;
u64 v = ((u64)x) << 32 | y;

unpack:

x = (u32)((v & 0xFFFFFFFF00000000) >> 32);
y = (u32)(v & 0xFFFFFFFF);
Jack
You don't need the explicit bitmasks when unpacking; `x = (u32)(v>>32); y = (u32)v;` does the job.
Mike Seymour
+2  A: 

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.

Williham Totland
+5  A: 

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));
lhf
+1 for not introducing types and bitshifts. I'd prefer assignments over `memcpy` though.
Michael Krelin - hacker
Those memcpys get optimised away under GCC and VC though ...
Goz
Goz, it's not about performance, it's about my (my!) perception of code beauty.
Michael Krelin - hacker
+1  A: 

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.

Viktor Sehr
+1 for the union, but it would be better to use standard fixed size types from `<stdint.h>`, i.e. `int32_t`, `int64_t`, since sizeof(long) and sizeof(long long) are not guaranteed to be any particular value.
Paul R
@Goz: how come?
Viktor Sehr
@Paul R: Good point, fixed it
Viktor Sehr
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
My 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
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
Viktor, not that it matters, but why do you add sizeof(*y*) to the address of x? ;-)
Michael Krelin - hacker
@Goz: because of the anonymous struct?, or cant you guaranteed anything with union?
Viktor Sehr
@Michael: mistake, updated to sizeof(x)
Viktor Sehr
@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
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
@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
Turning struct into array should please both Goz and standards and also rule out the possibility alignment troubles.
Michael Krelin - hacker
@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
@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
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
And yes, it is not safe, but programming is not!
Michael Krelin - hacker