【问题标题】:Problem converting endianness转换字节顺序的问题
【发布时间】:2011-07-28 18:18:06
【问题描述】:

我正在关注这个在 C++ 中使用 OpenAL 的教程:http://enigma-dev.org/forums/index.php?topic=730.0

正如您在教程中看到的,它们留下了一些未实现的方法,并且我在实现 file_read_int32_le(char*, FILE*) 和 file_read_int16_le(char*, FILE*) 时遇到了麻烦。显然它应该做的是从文件中加载 4 个字节(或者在 int16 的情况下加载 2 个字节),将其从小端转换为大端,然后将其作为无符号整数返回。代码如下:

static unsigned int file_read_int32_le(char* buffer, FILE* file) {
    size_t bytesRead = fread(buffer, 1, 4, file);
    printf("%x\n",(unsigned int)*buffer);
    unsigned int* newBuffer = (unsigned int*)malloc(4);
    *newBuffer = ((*buffer << 24) & 0xFF000000U) | ((*buffer << 8) & 0x00FF0000U) | ((*buffer >> 8) & 0x0000FF00U) | ((*buffer >> 24) & 0x000000FFU);
    printf("%x\n", *newBuffer);
    return (unsigned int)*newBuffer;
}

在调试时(在 XCode 中)它说 *buffer 的十六进制值是 0x72,它只有一个字节。当我使用 malloc(4) 创建 newBuffer 时,我得到一个 4 字节的缓冲区(*newBuffer 类似于 0xC0000003),然后在操作之后变为 0x72000000。我假设我正在寻找的结果是 0x00000027(编辑:实际上是 0x00000072),但我将如何实现呢? char* 缓冲区和 unsigned int* newBuffer 之间的转换是否与此有关?

【问题讨论】:

  • 实际上,该值将是 0x00000072,而不是 0x00000027。基本上,它是交换字节顺序,而不是 nybble 顺序。
  • 为什么该方法同时提供缓冲区和文件指针?这是不直观的。
  • 我不确定。这就是他们在教程中调用它的方式,所以我坚持使用他们对函数的声明。我同意这很奇怪。

标签: c++ xcode endianness openal


【解决方案1】:

是的,*buffer 将在 Xcode 的调试器中读取为 0x72,因为 buffer 是指向 char 的指针。

如果buffer指向的内存块的前四个字节是(十六进制)72 00 00 00,那么返回值应该是0x00000072,而不是0x00000027。字节应该被交换,但不是构成每个字节的两个“nybbles”。

这段代码泄露了你 malloc 的内存,反正你也不需要在这里 malloc。

您的字节交换在 PowerPC 或 68K Mac 上是正确的,但在 Intel Mac 或基于 ARM 的 iOS 上却不是。在这些平台上,您不必进行任何字节交换,因为它们本身就是 little-endian。

Core Foundation 提供了一种更轻松地完成这一切的方法:

static uint32_t file_read_int32_le(char* buffer, FILE* file) {
    fread(buffer, 1, 4, file);            // Get four bytes from the file
    uint32_t val = *(uint32_t*)buffer;    // Turn them into a 32-bit integer

    // Swap on a big-endian Mac, do nothing on a little-endian Mac or iOS
    return CFSwapInt32LittleToHost(val);
}

【讨论】:

    【解决方案2】:

    有一整套称为“htons/htonl/hton”的函数,它们的唯一目的就是将“主机”字节顺序转换为“网络”字节顺序。

    http://beej.us/guide/bgnet/output/html/multipage/htonsman.html

    每个函数都有一个相反的倒数。

    现在,这些函数不一定会对您有所帮助,因为它们本质上是从您的主机特定字节顺序转换而来的,因此请将此答案作为起点来查找您需要的内容。一般来说,代码不应该对它所处的架构做出假设。

    英特尔 == “小端”。 网络 == “大端”。

    希望这能让你走上正确的道路。

    【讨论】:

      【解决方案3】:

      我已将以下内容用于整数类型。在某些平台上,对于非整数类型是不安全的。

      template <typename T> T byte_reverse(T in) {
         T out;
         char* in_c = reinterpret_cast<char *>(&in);
         char* out_c = reinterpret_cast<char *>(&out);
         std::reverse_copy(in_c, in_c+sizeof(T), out_c);
         return out;
      };
      

      所以,把它放在你的文件阅读器中(你为什么要传入缓冲区,因为它看起来可能是临时的)

      static unsigned int file_read_int32_le(FILE* file) {
          unsigned int int_buffer;
          size_t bytesRead = fread(&int_buffer, 1, sizeof(int_buffer), file);
          /* Error or less than 4 bytes should be checked */
          return byte_reverse(int_buffer);
      }
      

      【讨论】:

        猜你喜欢
        • 2022-01-22
        • 1970-01-01
        • 1970-01-01
        • 2014-05-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多