5

我的任务是使用 C 将数据文件从大端转换为小端,反之亦然。我已经在网上寻找了大约 3 个小时来寻找其他示例并阅读我的教科书,但是我什至不知道如何开始这个功能。

到目前为止,我的事件顺序是正确的(1 到 4),但是在我的convert_and_save函数内部,我必须使用 → 创建一个 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);
    }
    
4

5 回答 5

7

这些不是标准功能(这些是 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*需要进一步参考

于 2014-07-21T02:40:51.937 回答
4

这是我为 Parrot VM 编写的函数之一,您可以从 parrotcode.org 下载 byteorder.c。可能有更短的方法可以做到这一点,但这适用于不同大小的整数,我们有一个宏来检测 PARROT_BIGENDIAN 中平台的字节顺序,你可以放弃所有这些。此外,如上所述,您可以搜索 htonl() ,它是 bigendian 硬件上的 nop,但在 little endian 上转换(只需获取 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
}
于 2014-07-21T02:30:31.360 回答
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 位数字(字符)不需要转换。

此外,这些仅针对无符号值定义,它们也适用于有符号整数。

对于浮点数和双精度数,与普通整数一样更困难,因为它们可能在主机字节顺序中,也可能不在。您可以在大端机器上获得小端浮点数,反之亦然。

其他编译器也有类似的内在函数。

例如,在GCC中,您可以直接调用:

   uint16_t __builtin_bswap16 (uint16_t x)
   uint32_t __builtin_bswap32 (uint32_t x)
   uint64_t __builtin_bswap64 (uint64_t x)
于 2014-07-21T02:49:57.127 回答
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;
    }
}
于 2014-07-21T02:43:50.283 回答
-1

您可能想看看这个答案,它显示了如何转换两种方式,以及不同的字节大小。这是一种方法,但在链接的线程中讨论了更有效的方法。

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);
于 2014-07-21T02:28:30.833 回答