C 40 位字节交换(endian)
C 40bit byte swap (endian)
我是 reading/writing little-endian 格式的二进制文件,来自 big-endian 使用 C 和 bswap_{ 16,32,64} 来自 byteswap.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 位的值以进行字节交换?
通过将 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)
编辑
我写这个宏得到了更好的性能(与我的初始代码相比,这产生了更少的汇编指令):
#define bswap40(s) \
((((s)&0xFF) << 32) | (((s)&0xFF00) << 16) | (((s)&0xFF0000)) | \
(((s)&0xFF000000) >> 16) | (((s)&0xFF00000000) >> 32))
使用:
s3.val_40 = bswap40(s3.val_40);
...但这可能是优化器问题。我认为他们应该针对同一件事进行优化。
原版Post
我更喜欢 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];
}
这是一个用于切换字节的破坏性内联函数...
I'm reading/writing a binary file in little-endian format from big-endian using C and bswap_{16,32,64} macros from byteswap.h for byte-swapping.
提出解决此问题的不同方法:更常见的是,代码需要读取已知字节序格式的文件,然后转换为代码的字节序。 可能涉及字节交换,编写在所有条件下都能工作的代码可能不是诀窍。
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;
不可移植。 int
、signed int
、unsigned
以外的类型的位范围不可移植,并且具有实现指定的行为。
顺便说一句:以 binary 模式打开文件:
// FILE *fp = fopen("index.bin", "w");
FILE *fp = fopen("index.bin", "wb");
我是 reading/writing little-endian 格式的二进制文件,来自 big-endian 使用 C 和 bswap_{ 16,32,64} 来自 byteswap.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 位的值以进行字节交换?
通过将 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)
编辑
我写这个宏得到了更好的性能(与我的初始代码相比,这产生了更少的汇编指令):
#define bswap40(s) \
((((s)&0xFF) << 32) | (((s)&0xFF00) << 16) | (((s)&0xFF0000)) | \
(((s)&0xFF000000) >> 16) | (((s)&0xFF00000000) >> 32))
使用:
s3.val_40 = bswap40(s3.val_40);
...但这可能是优化器问题。我认为他们应该针对同一件事进行优化。
原版Post
我更喜欢 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];
}
这是一个用于切换字节的破坏性内联函数...
I'm reading/writing a binary file in little-endian format from big-endian using C and bswap_{16,32,64} macros from byteswap.h for byte-swapping.
提出解决此问题的不同方法:更常见的是,代码需要读取已知字节序格式的文件,然后转换为代码的字节序。 可能涉及字节交换,编写在所有条件下都能工作的代码可能不是诀窍。
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;
不可移植。 int
、signed int
、unsigned
以外的类型的位范围不可移植,并且具有实现指定的行为。
顺便说一句:以 binary 模式打开文件:
// FILE *fp = fopen("index.bin", "w");
FILE *fp = fopen("index.bin", "wb");