我有四个字节数组,我想在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]);
什么是正确的方法?
答案 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可能是安全的。