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

时间:2014-07-21 02:14:46

标签: c endianness converters

我的任务是将数据文件从big endian转换为little endian&反之亦然使用C.我已经在网上寻找其他示例和阅读我的教科书大约3个小时了,但是我对如何开始这个功能感到困惑。

到目前为止,我的事件顺序正确(1到4),但在我的convert_and_save函数中我是否必须使用→char buffer[4];创建一个char数组?

有人可以帮帮我吗?即使你只是给我一些关于查找内容的线索,我也会非常感激。

我需要编写一个名为:

的函数
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);
    }
    

5 个答案:

答案 0 :(得分:4)

我为Parrot VM编写的这个函数之一,您可以从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
}

答案 1 :(得分:4)

这些不是标准功能(这些是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()

Visual Studio

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 *需要进一步参考

答案 2 :(得分:2)

看一下这个答案: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)

答案 3 :(得分:1)

这是我的样本。它会反转整数的字节顺序。请注意,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;
    }
}

答案 4 :(得分:-1)

您可能需要查看this answer,其中显示了如何转换两种方式,也使用不同的字节大小。 这是一种方法,但在链接的线程中讨论了更有效的方法。

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