C 40位字节交换(字节序)

时间:2016-06-28 17:01:40

标签: c swap endianness bit-fields

我正在使用来自byteswap的C和bswap_ {16,32,64}宏从 big-endian 读取/编写 little-endian 格式的二进制文件。 h用于字节交换。

除了40位的位字段外,所有值都被正确读写。

bswap_40宏不存在,我不知道它是怎么做的,或者是否有更好的解决方案。

这是一个显示此问题的小代码:

#include <stdio.h>
#include <inttypes.h>
#include <byteswap.h>

#define bswap_40(x) bswap_64(x)

struct tIndex {
  uint64_t val_64;
  uint64_t val_40:40;
} s1 = { 5294967296, 5294967296 };

int main(void)
{
    // write swapped values
    struct tIndex s2 = { bswap_64(s1.val_64), bswap_40(s1.val_40) };
    FILE *fp = fopen("index.bin", "w");
    fwrite(&s2, sizeof(s2), 1, fp);
    fclose(fp);

    // read swapped values
    struct tIndex s3;
    fp = fopen("index.bin", "r");
    fread(&s3, sizeof(s3), 1, fp);
    fclose(fp);
    s3.val_64 = bswap_64(s3.val_64);
    s3.val_40 = bswap_40(s3.val_40);

    printf("val_64: %" PRIu64 " -> %s\n", s3.val_64, (s1.val_64 == s3.val_64 ? "OK" : "Error"));
    printf("val_40: %" PRIu64 " -> %s\n", s3.val_40, (s1.val_40 == s3.val_40 ? "OK" : "Error"));

    return 0;
}

该代码编译为:

  

gcc -D_FILE_OFFSET_BITS = 64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE   swap_40.c -o swap_40

如何定义bswap_40宏来读取和写入40位进行字节交换的值?

3 个答案:

答案 0 :(得分:6)

通过将bswap_40定义为与bswap_64相同,您可以交换8个字节而不是5个字节。所以如果你从这开始:

00 00 00 01 02 03 04 05

你最终得到了这个:

05 04 03 02 01 00 00 00

而不是:

00 00 00 05 04 03 02 01

处理此问题的最简单方法是取bswap_64的结果并将其右移24:

#define bswap_40(x) (bswap_64(x) >> 24)

答案 1 :(得分:1)

修改

我写这个宏的性能更好(与我的初始代码相比,这产生了更少的汇编指令):

#define bswap40(s)                                                \
  ((((s)&0xFF) << 32) | (((s)&0xFF00) << 16) | (((s)&0xFF0000)) | \
   (((s)&0xFF000000) >> 16) | (((s)&0xFF00000000) >> 32))

使用:

s3.val_40 = bswap40(s3.val_40);

...但它可能是一个优化器问题。我认为他们应该针对同样的事情进行优化。

原帖

我更喜欢dbush的答案......我准备写这个:

static inline void bswap40(void* s) {
  uint8_t* bytes = s;
  bytes[0] ^= bytes[3];
  bytes[1] ^= bytes[2];
  bytes[3] ^= bytes[0];
  bytes[2] ^= bytes[1];
  bytes[0] ^= bytes[3];
  bytes[1] ^= bytes[2];
}

它是用于切换字节的破坏性内联函数...

答案 2 :(得分:0)

  

我正在使用C和bswap_ {16,32,64}来自byteswap.h的宏从big-endian读取/编写一个小端格式的二进制文件,用于字节交换。

建议一种解决此问题的不同方法:更常见的是,代码需要以已知的endian格式读取文件,然后转换为代码的endian。这个可能涉及字节交换,可能不是编写在所有条件下都能工作的代码。

 unsigned char file_data[5];
 // file data is in big endidan
 fread(file_data, sizeof file_data, 1, fp);

 uint64_t y = 0;
 for (i=0; i<sizeof file_data; i++) {
   y <<= 8;
   y |= file_data[i];
 }

 printf("val_64: %" PRIu64 "\n", y);

uint64_t val_40:40;不可移植。 intsigned intunsigned不可移植且具有实现指定行为的其他类型的位范围。

BTW:以二进制模式打开文件:

// FILE *fp = fopen("index.bin", "w");
FILE *fp = fopen("index.bin", "wb");