转换字节序的问题

时间:2011-07-28 18:18:06

标签: c++ xcode endianness openal

我正在按照本教程在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,我猜...),将它从little-endian转换为big endian然后将其作为无符号整数返回。这是代码:

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 * buffer和unsigned int * newBuffer之间的转换有关?

3 个答案:

答案 0 :(得分:1)

有一系列称为“htons / htonl / hton”的函数,其唯一目的是将“主机”转换为“网络”字节顺序。

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

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

现在,这些函数无法帮助您,因为它们本质上是从您的主机特定字节顺序转换的,所以请使用此答案作为查找所需内容的起点。通常,代码不应该假设它所处的架构。

Intel ==“Little Endian”。 网络==“Big Endian”。

希望这能让你走上正轨。

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

如果缓冲区指向的内存块中的前四个字节是(十六进制)72 00 00 00,则返回值应为0x00000072,而不是0x00000027。字节应该被交换,而不是组成每个字节的两个“nybbles”。

此代码泄露了malloc'd的内存,无论如何你都不需要malloc。

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

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