简体   繁体   English

如何将四个16位uint编码为一个64位uint,然后再次对其进行解码?

[英]How can I encode four 16 bit uints into a 64 bit uint, and decode them again?

I wrote this function with the help of this page on bit twiddling : 我在这个页面的帮助下编写了此功能:

uint16_t *decode(uint64_t instr) {
  // decode instr (this is new to me lol)
  uint16_t icode = (instr >> 48) & ((1 << 16) - 1);
  uint16_t p1    = (instr >> 32) & ((1 << 16) - 1);
  uint16_t p2    = (instr >> 16) & ((1 << 16) - 1);
  uint16_t p3    = (instr >> 00) & ((1 << 16) - 1);

  return (uint16_t[]){icode, p1, p2, p3};
}

I have this to test it: 我有这个来测试它:

uint16_t *arr = decode(number);
for(int i = 0; i < 4; i++) {
  printf("%d\n", arr[i]);
}

However, this prints 0 four times whatever number is. 但是,无论numbernumber ,这都会打印四次0。 I also haven't solved the first part of the question, how to encode the four uint16_t's in the first place. 我也没有解决问题的第一部分,即如何首先编码四个uint16_t。

how to encode the four uint16_t's in the first place 首先如何编码四个uint16_t

This isn't hard. 这不难。 All you have to do is to load each uint16_t to a uint64_t one-by-one, and then return that uint64_t : 您要做的就是将每个uint16_t加载到uint64_t ,然后返回该uint64_t

uint64_t encode(uint16_t uints[]) {
    uint64_t master = 0;
    for (uint8_t index = 0; index <= 3; ++index) {
        master <<= 16; // Shift master left by 16 bits to create space for the next uint16
        master |= uints[index]; // Load uints[index] to the lower 16 bits of master
    } // Do this four times
    return master;
}

To load the uint16_t s in reverse order, simply replace uint8_t index = 0; index <= 3; ++index 要以相反的顺序加载uint16_t ,只需替换uint8_t index = 0; index <= 3; ++index uint8_t index = 0; index <= 3; ++index uint8_t index = 0; index <= 3; ++index with uint8_t index = 3; index >= 0; --index 带有uint8_t index = 3; index >= 0; --index uint8_t index = 0; index <= 3; ++index uint8_t index = 3; index >= 0; --index uint8_t index = 3; index >= 0; --index uint8_t index = 3; index >= 0; --index . uint8_t index = 3; index >= 0; --index

Your best bet is actually to use memcpy . 最好的选择实际上是使用memcpy Most modern compilers will optimize this into the necessary bit shifts and such for you. 大多数现代的编译器都会将此优化为必要的位移,并为您量身定制。

uint64_t pack(const uint16_t arr[static 4]) {
    uint64_t res;
    memcpy(&res, arr, 8);
    return res;
}

void unpack(uint64_t v, uint16_t arr[static 4]) {
    memcpy(arr, &v, 8);
}

Note that the result is endian-dependent, appropriate for packing and unpacking on the same machine. 请注意,结果取决于字节序,适合在同一台机器上打包和拆包。 Note too that I'm using the static array specifier to check that the caller passes at least 4 elements (when such checking is possible); 还要注意,我正在使用static数组说明符来检查调用方是否通过了至少4个元素(当可以进行这种检查时); if that gives your compiler grief, just remove the static specifier. 如果那使您的编译器感到悲伤,只需删除static说明符即可。

First, you can't pass an array back from a function the way you currently have it (which is why you're getting 0's), you'll need to pass it via pointer or static reference. 首先,您不能以当前使用的方式将数组从函数传递回去(这就是为什么要得到0的原因),您需要通过指针或静态引用传递它。

However, since you're dealing with 2 known bit-widths, you can use a mask and shift off that: 但是,由于要处理2个已知的位宽,因此可以使用掩码并将其移开:

out[0] = val & 0x000000000000FFFF; // 1st word
out[1] = (val & 0x00000000FFFF0000) >> 16; // 2nd word
out[2] = (val & 0x0000FFFF00000000) >> 32; // 3rd word
out[3] = (val & 0xFFFF000000000000) >> 48; // 4th word

You could put this in a function or macro: 您可以将其放在函数或宏中:

#define MACRO_DECODE(val, arr) arr[0]= val & 0x000000000000FFFF; \
                      arr[1] = (val & 0x00000000FFFF0000) >> 16; \
                      arr[2] = (val & 0x0000FFFF00000000) >> 32; \
                      arr[3] = (val & 0xFFFF000000000000) >> 48;

void decode(uint64_t val, uint16_t *out)
{
    out[0] = val & 0x000000000000FFFF;
    out[1] = (val & 0x00000000FFFF0000) >> 16;
    out[2] = (val & 0x0000FFFF00000000) >> 32;
    out[3] = (val & 0xFFFF000000000000) >> 48;
}


int main(int argc, char** argv)
{
    int i;
    uint16_t arr[] = { 0, 0, 0, 0} ;
    for (i = 0; i < 4; ++i) {
        printf("%#06x = %d\n", arr[i], arr[i]);
    }

    // as a function
    decode(0xAAAABBBBCCCCDDDD, arr);

    for (i = 0; i < 4; ++i) {
        printf("%#06x = %d\n", arr[i], arr[i]);
    }

    // as a macro
    MACRO_DECODE(0xDDDDCCCCBBBBAAAA, arr);
    for (i = 0; i < 4; ++i) {
        printf("%#06x = %d\n", arr[i], arr[i]);
    }
    return 0;
}

Additionally, you could use memcpy : 另外,您可以使用memcpy

int main(int argc, char** argv)
{
    int i;
    uint16_t arr[] = { 0, 0, 0, 0} ;
    uint64_t src = 0xAAAABBBBCCCCDDDD;
    for (i = 0; i < 4; ++i) {
        printf("%#06x = %d\n", arr[i], arr[i]);
    }

    // memcpy
    memcpy(arr, &src, sizeof(arr));

    for (i = 0; i < 4; ++i) {
        printf("%#06x = %d\n", arr[i], arr[i]);
    }
    return 0;
}

Hope that can help. 希望能对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM