如何在Objective C中将四字节数组转换为float?

时间:2018-01-09 14:26:14

标签: objective-c

我有四个字节数组,我想在Objective C中转换为float。 我尝试了三种方法,但不确定什么是正确的方法。

我尝试的是

        unsigned char *bytearray = (unsigned char *)calloc(4, sizeof(unsigned char));
        bytearray[0] = GolfResult[i]; bytearray[1] = GolfResult[i+1]; bytearray[2] = GolfResult[i+2]; bytearray[3] = GolfResult[i+3];

    Method 1

        float result = [[NSNumber numberWithUnsignedChar:*bytearray] floatValue];

    Method 2

        float result = (float)((bytearray[3] << 24) | (bytearray[2] << 16) | (bytearray[1] << 8) | bytearray[0]);

    Method 3
        float result = (float)((bytearray[0] << 24) | (bytearray[1] << 16) | (bytearray[2] << 8) | bytearray[3]);

什么是正确的方法?

1 个答案:

答案 0 :(得分:2)

不幸的是,没有一个方法是正确的,因为它们都以某种方式将字节解释为整数,然后尝试将该整数转换为浮点数。这永远不会给出正确的答案,因为整数值的字节,比如42(0x2A位模式),与等效浮点值的字节非常不同,比如42.0(0x42280000位模式,它作为int加载并转换为float产生1109917696.0)。

所需要的是将字节直接解释为浮点格式。

您必须处理的下一个问题是字节的顺序,因为它们存储在golfResult (1)数组中。根据这些字节的来源,第一个(golfResult[i])可能是最少( little endian )或大多数( big endian )有效字节。如果以错误的顺序组合4个字节,那么结果浮点值将不正确(2)

可以,我们提供的代码使用整数类型变量作为 n 字节的存储,而不将它们视为整数本身< / em>的。也就是说,如果你有一个int32_t *类型的指针,从中加载一个值并将其存储在int32_t变量中,那么你只需要将4个字节从一个位置复制到另一个位置保留

Apple提供Byte Order Utilities函数来重新排列字节顺序,CFSwapInt32BigToHost()CFSwapInt32LittleToHost()中的一个应该用于将您的4个字节命令为您的主机平台正在使用的任何顺序(注意你不需要知道主机顺序,小端或大端,这些功能都知道;你只需要知道golfResult中的顺序。

最后,重要的是要知道calloc()malloc()和朋友返回指针“对齐以便可以用于任何数据类型”(请参阅​​{{1}中的man 3 malloc }})。这意味着你可以强制转换这个指针作为指向任何类型和加载/存储的指针而没有内存对齐问题。

现在可能所有声音都很复杂,但在代码中它很简单。从生成Terminal开始,保留字节的顺序:

bytearray

现在执行字节的加载,字节交换和浮点解释

unsigned char *bytearray = (unsigned char *)calloc(4, sizeof(unsigned char));
bytearray[0] = GolfResult[i]; bytearray[1] = GolfResult[i+1]; bytearray[2] = GolfResult[i+2]; bytearray[3] = GolfResult[i+3];

希望帮助超过它的困惑!

注意:

(1)您是否注意到变量// - cast bytearray to be a pointer to // int32_t (used here ONLY as a 4 byte container and NOT as // an integer *per se*) then copy the 4 bytes to unorderedBytes // so the four bytes are in the same order as in bytearray. int32_t unorderedBytes = *(int32_t *)bytearray; // - pass those four bytes to a function to reorder them to host // endian order, here we pick CFSwapInt32LittleToHost, you might // require CFSwapInt32BigToHost int32_t orderedBytes = CFSwapInt32LittleToHost(unorderedBytes); // now cast the *address* of the host-ordered four bytes to // be a float pointer and load them, interpreting them correctly float output = *(float *)&orderedBytes; 为蓝色?这是因为您没有遵循使用小写字母开始变量的命名约定。

(2)我们这里只处理字节顺序,我们忽略二进制格式。大多数系统使用IEEE浮点格式,如果GolfResult中的字节来自哪里不使用IEEE,则​​您需要解释它们使用的任何格式时会遇到更大的问题。假设IEEE可能是安全的。