C 40位字节交换(endian)

C 40位字节交换(endian),c,swap,endianness,bit-fields,C,Swap,Endianness,Bit Fields,我正在使用byteswap.h中的C和bswap_{16,32,64}宏从big-endian读取/写入一个小endian格式的二进制文件,用于字节交换 除40位的位字段外,所有值均正确读取和写入 bswap\u 40宏不存在,我不知道如何实现,也不知道是否有更好的解决方案 下面是显示此问题的小代码: #include <stdio.h> #include <inttypes.h> #include <byteswap.h> #define bswap_40

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

除40位的位字段外,所有值均正确读取和写入

bswap\u 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;
}
#包括
#包括
#包括
#定义bswap_40(x)bswap_64(x)
结构tIndex{
uint64_t val_64;
uint64:40;
}s1={5294967296,5294967296};
内部主(空)
{
//写交换值
结构tIndex s2={bswap_64(s1.val_64),bswap_40(s1.val_40)};
文件*fp=fopen(“index.bin”,“w”);
fwrite(&s2,sizeof(s2),1,fp);
fclose(fp);
//读取交换的值
结构tIndex s3;
fp=fopen(“索引箱”、“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?“确定”:“错误”);
printf(“val_40:%“PRIu64”->%s\n”,s3.val_40,(s1.val_40==s3.val_40?“确定”:“错误”);
返回0;
}
该代码由以下代码编译:

gcc-D_文件\u偏移量\u位=64-D_大文件\u源-D_大文件64\u源 交换40.c-o交换40


如何定义
bswap\u 40
宏,以便在执行字节交换时读取和写入这些40位的值?

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

00 00 00 01 02 03 04 05
05 04 03 02 01 00 00 00
你会得到这样的结果:

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)
编辑

编写此宏时,我获得了更好的性能(与我的初始代码相比,生成的汇编指令更少):

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

原创帖子

我更喜欢德布什的答案。。。我正要写这封信:

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];
}
这是一个破坏性的内联函数,用于切换字节

我正在使用byteswap.h中的C和bswap_{16,32,64}宏从big-endian读取/写入一个小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);

谢谢,优化的版本很有趣。
// FILE *fp = fopen("index.bin", "w");
FILE *fp = fopen("index.bin", "wb");