如何重新排序整数的字节?

我的任务是使用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); 

在这个函数里面我做了以下一系列步骤:

  1. 使用以下方法将整数转换为字符数组:

     int integer_to_characters(int number, char * buffer) { memcpy(buffer, &number, 4); } 
  2. 反转该数组中字符的顺序。

  3. 使用以下方法将字符数组转换回整数:

     int characters_to_integer(char * buffer) { int result; memcpy(&result, buffer, 4); return result; } 
  4. 使用以下方法在输出文件上写入转换后的记录

     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);