如何重新排序整数的字节?
我的任务是使用C将数据文件从big endian转换为little endian,反之亦然。我已经在线查看了大约3个小时的其他示例和阅读我的教科书,但是我很困惑甚至如何开始这个function。
到目前为止,我的事件顺序是正确的(1到4),但在我的convert_and_save
函数中,我必须使用→ char buffer[4];
创建一个char数组char buffer[4];
?
有人可以帮帮我吗? 即使你只是给我一些关于查找内容的线索,我也会非常感激。
我需要编写一个名为的函数:
void convert_and_save(struct record item, FILE * output_handle, int number);
在这个函数里面我做了以下一系列步骤:
-
使用以下方法将整数转换为字符数组:
int integer_to_characters(int number, char * buffer) { memcpy(buffer, &number, 4); }
-
反转该数组中字符的顺序。
-
使用以下方法将字符数组转换回整数:
int characters_to_integer(char * buffer) { int result; memcpy(&result, buffer, 4); return result; }
-
使用以下方法在输出文件上写入转换后的记录
void save_record(FILE * file_handle, struct record a) { char output_buffer[size_of_record]; integer_to_characters(a.age, &(output_buffer[0])); memcpy(&(output_buffer[4]), a.name, 12); integer_to_characters(a.department, &(output_buffer[16])); fwrite(output_buffer, sizeof(char), size_of_record, file_handle); }
我为Parrot VM编写的这个function之一,您可以从parrotcode.org下载byteorder.c。 可能有更短的方法,但这适用于不同大小的整数,我们有一个宏来检测PARROT_BIGENDIAN平台的字节顺序,你可以丢弃所有这些。 另外,如上所述,您可以搜索hintonl(),这是bigendian硬件上的nop,但转换为小端(只需获取Linux x86实现)
INTVAL fetch_iv_le(INTVAL w) { ASSERT_ARGS(fetch_iv_le) #if !PARROT_BIGENDIAN return w; // No-op on little endian hardware #else # if INTVAL_SIZE == 4 return (w << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | (w >> 24); # else # if INTVAL_SIZE == 8 INTVAL r; r = w << 56; r |= (w & 0xff00) << 40; r |= (w & 0xff0000) << 24; r |= (w & 0xff000000) << 8; r |= (w & 0xff00000000) >> 8; r |= (w & 0xff0000000000) >> 24; r |= (w & 0xff000000000000) >> 40; r |= (w & 0xff00000000000000) >> 56; return r; # endif # endif #endif }
这些不是标准function(这些是gcc扩展),但您可以使用它们:
– 内置函数:uint16_t __builtin_bswap16(uint16_t x)返回x,字节顺序颠倒; 例如,0xaabb变为0xbbaa。 这里的字节总是意味着8位。
– 内置函数:uint32_t __builtin_bswap32(uint32_t x)与__builtin_bswap16类似,但参数和返回类型为32位。
– 内置函数:uint64_t __builtin_bswap64(uint64_t x)与__builtin_bswap32类似,但参数和返回类型为64位。
如果你可以使用这些,很可能会为你的平台带来更优化的代码,如果没有,干得好,提交补丁到gcc 🙂
Clang还有__builtin_bswap16() __builtin_bswap32() __builtin_bswap64()
视觉工作室
unsigned short _byteswap_ushort ( unsigned short val ); unsigned long _byteswap_ulong ( unsigned long val ); unsigned __int64 _byteswap_uint64 ( unsigned __int64 val );
ICC有_bswap16, _bswap and _bswap64
*需要进一步参考
看看这个答案: https : //stackoverflow.com/a/105339/1461424
如果您使用的是Visual C ++,请执行以下操作:包含intrin.h并调用以下函数:
对于16位数字:
unsigned short _byteswap_ushort(unsigned short value);
对于32位数字:
unsigned long _byteswap_ulong(unsigned long value);
对于64位数字:
unsigned __int64 _byteswap_uint64(unsigned __int64 value);
不需要转换8位数字(字符)。
此外,这些仅针对无符号值定义,它们也适用于有符号整数。
对于浮点数和双精度数,它与普通整数一样困难,因为这些可能与否可能在主机的字节顺序中。 您可以在big-endian机器上获得little-endian浮点数,反之亦然。
其他编译器也有类似的内在函数。
以GCC为例,您可以直接致电:
uint16_t __builtin_bswap16 (uint16_t x) uint32_t __builtin_bswap32 (uint32_t x) uint64_t __builtin_bswap64 (uint64_t x)
这是我的样本。 它会反转整数的字节顺序。 请注意,C未指定int的大小。 它可以是16,32,64 …如果你想确保尺寸,使用(uint_16t,uint_32t,uint_64t),
void reverse_endianess(int* number) { char byte_arr[8] = {0}; int i; for (i=0; i < sizeof(int); i++) { byte_arr[i] = (*number & 0xFF); *number = *number >> 8; } *number = 0; for (i=0; i < sizeof(int); i++) { *number |= byte_arr[i]; *number = *number << 8; } }
您可能需要查看此答案 , 该答案显示了如何转换两种方式,也使用不同的字节大小。 这是一种方法,但在链接的线程中讨论了更有效的方法。
uint32_t num = 9; uint32_t b0,b1,b2,b3,b4,b5,b6,b7; uint32_t res = 0; b0 = (num & 0xf) << 28; b1 = (num & 0xf0) << 24; b2 = (num & 0xf00) << 20; b3 = (num & 0xf000) << 16; b4 = (num & 0xf0000) << 12; b5 = (num & 0xf00000) << 8; b6 = (num & 0xf000000) << 4; b7 = (num & 0xf0000000) << 4; res = b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7; printf("%d\n", res);