我试图从eeprom重建一个32位浮点值。
eeprom存储器(0-4)中的4个字节是:B4 A2 91 4D
并且PC(VS Studio)正确地将其重建为3.054199 * 10 ^ 8(我知道浮点值应该在那里)
现在我将这个eeprom从8位Arduino中读取,所以不确定它是否是编译器/平台的东西,但是当我尝试将4个字节读入32位双字节时,然后将它转换为浮点数,我得到的值甚至不接近。
假设转换不能使用标准的ansi-c编译器自动完成,那么如何将4个字节手动解析成浮点数?
答案 0 :(得分:10)
最安全的方式,也是由于编译器优化也和其他任何方法一样快,是使用memcpy
:
uint32_t dword = 0x4D91A2B4;
float f;
memcpy(&f, &dw, 4);
答案 1 :(得分:1)
正如Shafik Yaghmour在他的回答中提到的那样 - 它可能是一个endianness问题,因为这是您在这种低级别操作中遇到的唯一逻辑问题。虽然Shafiks answer在他所关联的问题中,基本上涵盖了处理此类问题的过程,但我只是给您留下一些信息:
在Anduino论坛上作为stated,Anduino使用 Little Endian 。如果您不确定系统的最终结果是什么,而您希望将代码设置为半多平台,则可以使用简单的代码片段在运行时检查字节顺序:
bool isBigEndian(){
int number = 1;
return (*(char*)&number != 1);
}
请注意 - 就像所有事情一样 - 这会消耗你的一些处理器时间并使你的程序运行得更慢,虽然这几乎总是一件坏事,你仍然可以使用它来查看调试中的结果你的应用版本。
这是如何工作的,它测试存储在int
指向的地址的&number
的第一个字节。如果第一个字节不是1
,则表示字节为 Big Endian 。
此外 - 仅在sizeof(int) > sizeof(char)
时才有效。
您也可以将其嵌入代码中:
float getFromEeprom(int address){
char bytes[sizeof(float)];
if(isBigEndian()){
for(int i=0;i<sizeof(float);i++)
bytes[sizeof(float)-i] = EEPROM.read(address+i);
}
else{
for(int i=0;i<sizeof(float);i++)
bytes[i] = EEPROM.read(address+i);
}
float result;
memcpy(&result, bytes, sizeof(float));
return result;
}
答案 2 :(得分:0)
你需要在指针级别进行强制转换。
int myFourBytes = /* something */;
float* myFloat = (float*) &myFourBytes;
cout << *myFloat;
应该工作。
如果数据是在存储相反字节序的值的其他平台上生成的,则您需要手动交换字节。 E.g:
unsigned char myFourBytes[4] = { 0xB4, 0xA2, 0x91, 0x4D };
std::swap(myFourBytes[0], myFourBytes[3]);
std::swap(myFourBytes[1], myFourBytes[2]);