Как сохранить 64-битное целое число в двух 32-битных целых и преобразовать обратно

Я почти уверен, что это просто вопрос о побитовых операциях, но я не совсем уверен, что именно я должен делать, и все поиски возвращают "64 бит против 32 бит".

8 ответов

Решение

Упаковка:

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

распаковать:

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

Или это, если вам не интересно, что означают два 32-битных числа:

u32 x[2];
u64 z;
memcpy(x,&z,sizeof(z));
memcpy(&z,x,sizeof(z));

Используйте объединение и избавьтесь от битовых операций:

<stdint.h> // for int32_t, int64_t

union {
  int64_t big;
  struct {
    int32_t x;
    int32_t y;
  };
};
assert(&y == &x + sizeof(x));

просто как тот. большой состоит из х и у.

Я не знаю, лучше ли это, чем решения union или memcpy, но я должен был распаковать / упаковать 64-битные целые числа со знаком и не хотел ничего маскировать или сдвигать, поэтому я просто обработал 64-битное значение как два 32-битные значения и назначить их напрямую так:

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

Основной метод заключается в следующем:

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

Обратите внимание, что ваши целые числа должны быть без знака; или операции не определены.

Вкратце от user204847 и user121747 , без использования приведения в стиле C:

Переменные:

      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;

Не уверен, что этот способ хорош для переносимости или других, но я использую...

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

Мне нравится, как я это делаю, так как это предлагает большую готовность и может быть применено разными способами, т.е. 02x32, 04x16, 08x08 и т. д. Я новичок в C, поэтому не стесняйтесь критиковать мой код и способ его выполнения... спасибо

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;
Другие вопросы по тегам