开发者

How to store a 64 bit integer in two 32 bit integers and convert back again

开发者 https://www.devze.com 2022-12-29 17:59 出处:网络
I\'m pretty sure its just a matter of some bitwise operations, I\'m just not entirely sure of exactly开发者_JS百科 what I should be doing, and all searches return back \"64 bit vs 32 bit\".pack:

I'm pretty sure its just a matter of some bitwise operations, I'm just not entirely sure of exactly开发者_JS百科 what I should be doing, and all searches return back "64 bit vs 32 bit".


pack:

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

unpack:

x = (u32)((v & 0xFFFFFFFF00000000LL) >> 32);
y = (u32)(v & 0xFFFFFFFFLL);


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));


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.


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);
}


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.


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;


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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号