【问题标题】:Converting a struct of 4 integers to a float将 4 个整数的结构转换为浮点数
【发布时间】:2019-01-21 07:03:52
【问题描述】:

我是编程新手,我不擅长指针和类型转换,所以我需要一些帮助。

我正在使用 IAR Workbench 和 STM32L475。 在从 EEprom 加载它们之后,我正在尝试将结构中的 4 个字节转换为浮点数。

我知道 Big/Little Endian 和将代码移植到其他 micro's 可能会遇到挑战,但请不要把这个线程弄乱,因为这对我来说现在并不重要。

我做错了什么,谢谢你的帮助?

请保持简单并解释“傻瓜”。

我收到 pe513 错误。

我的代码:

struct Test {
    uint8_t Byte1;
    uint8_t Byte2;
    uint8_t Byte3;
    uint8_t Byte4;
} TestStruct;

float x = 0.0;

uint8_t *TestStruct_ptr;

int main(void)
{
    /* USER CODE BEGIN 1 */
    TestStruct.Byte1 = 0x41; //float value = 23.10
    TestStruct.Byte2 = 0xB8;
    TestStruct.Byte3 = 0xCC;
    TestStruct.Byte4 = 0xCD;  

    TestStruct_ptr = (float*)&TestStruct;

    x = (float*) TestStruct_ptr;

    // some code



    return 0;
}

编辑: 我正在从 Eeprom 加载一个数组,并且必须将四个 uint8 字节的数组“收集”到一个浮点数,它们在保存到 Eeprom 之前是结构的一部分。 明天上班时,我会更新确切的错误消息。

我最终使用了“联合”,因为这似乎是最好的解决方案。

我的示例代码现在如下所示:

union Eeprom {
  struct {
    uint8_t Byte1;
    uint8_t Byte2;
    uint8_t Byte3;
    uint8_t Byte4;
  };
  float x;
  uint8_t Array[4];
};


int main(void)
{

  union Eeprom Test;

  //assign values to individual bytes
  Test.Byte1=0xCD; 
  Test.Byte2=0xCC;
  Test.Byte3=0xB8;
  Test.Byte4=0x41;

  //Assign values as an array (here individual bytes, overwrites above assigned values).
  //Data will be formatted as an array when loaded from E2prom.
  Test.Array[0]=0xCD;  
  Test.Array[1]=0xCC;
  Test.Array[2]=0xB8;
  Test.Array[3]=0x41;

  //Assign value as floating point value (overwrites the above assigned values)
  Test.x = 23.1;  

  printf("FPvalue %3.2f \n Byte1 %x\n Byte2 %x\n Byte3 %x\n Byte4 %x\n 
    Array[0] %x\n Array[1] %x\n Array[2] %x\n Array[3] %x\n",
    Test.x, Test.Byte1, Test.Byte2, Test.Byte3, Test.Byte4, 
    Test.Array[0], Test.Array[1], Test.Array[2], Test.Array[3]);
}

输出如下所示:

floatvalue 23.10 
Byte1 cd
Byte2 cc
Byte3 b8
Byte4 41
Array[0] cd
Array[1] cc
Array[2] b8
Array[3] 41

【问题讨论】:

  • “我收到 pe513 错误。” 这太神秘了,任何人都无法记住它的含义。请edit 并在您的问题中添加完整错误消息。
  • TestStruct_ptr = (float*)&TestStruct; violates strict aliasing 是未定义的行为。 TestStruct 不是 float 并且不能作为一个来处理。
  • 我不清楚。您是想将 4 int 转换为 4 float、4 int 转换为单个 float,还是将整个 struct 内容转换为单个 float 值?
  • 为什么不用float类型而不是把数据类型从int改成float呢?
  • @Lundin 假设 address 当然是正确对齐的!

标签: c pointers type-conversion stm32


【解决方案1】:

由于您不关心可移植性或字节顺序问题,您可以简单地使用 memcpy 复制字节:

memcpy(&x, &TestStruct, sizeof x);

您可能在某处看到过此选项或类似选项:

x = *(float*)&TestStruct;  // BAD!!!!! dereferencing using wrong pointer type

不要这样做!它违反了严格的别名规则,这是未定义的行为

【讨论】:

  • 我建议memcpy(&x, &TestStruct, sizeof x);
  • @P__J__ 是的sizeof x 更好。我认为sizeof float 甚至不会编译(应该是sizeof(float))。
  • @user694733 sizeof floatsizeof(float) 都是正确的。见6.5.3 Unary operators6.5.3.4 The sizeof and _Alignof operators
  • @AndrewHenle 不,sizeof type-name 不满足 6.5.3 中 unary-expression 的语法。
  • @IanAbbott 我错过了这里的上下文。而就是为什么我总是使用()sizeof
【解决方案2】:

以这种方式输入双关语是非法的。正如其他人所提到的,联合可用于进行类型双关。或者,由于意图似乎是有一个字节可访问的浮点数,因此将char 类型键入 是合法的。因此,与其将变量的类型声明为 4 个 chars 的结构,不如将其声明为 float,然后键入双关语为 unsigned char 并将其作为数组访问:

float x = 0.0;

unsigned char *test_ptr = (unsigned char *)&x;

int main(void)
{
    /* USER CODE BEGIN 1 */
    test_ptr[0] = 0x41; //float value = 23.10
    test_ptr[1] = 0xB8;
    test_ptr[2] = 0xCC;
    test_ptr[3] = 0xCD;  

    // some code

    return 0;
}

当然,字节的顺序将取决于字节序。我保留了您的字节顺序,这对于大端目标应该是正确的。

【讨论】:

  • 它违反了严格的别名规则,应该避免
  • @P__J__ char 类型是别名规则的一个例外。请参阅 C11 标准第 6.5 节第 7 段。对象的存储值只能由具有以下类型之一的左值表达式访问:[...] --a 字符类型
  • 对不起,我不明白这是如何解决问题的。
  • pe513 似乎是 IAR 吐出的一个错误,与我在其上进行的简短搜索中打破严格别名有关。因为字符类型允许为其他类型设置别名(但不能反过来),如果 IAR 编译器符合 C 标准,这不会导致严格的别名错误。关于使用unions 的其他答案也应该可以解决这个问题。
【解决方案3】:

联盟双关语就可以了。

typedef union
{
    uint32_t u32;
    uint16_t u16[2];
    uint8_t  u8[4];
    float    f;
}b32data;

当您从 NV 内存中读取时,只需分配正确的成员,而无需任何指针。

【讨论】:

  • 我不确定这是否能解决我的问题,“输入”格式是 4 个 uint8 字节存储在一个数组中,就像我制作的结构一样。
  • @Peter1 你知道C吗?或者您从某处复制代码 - 在该评论之后更可能是 IMO
  • 这不应该是一个大惊喜,因为我的问题以“我是编程新手,我不擅长指针”开头。是的,我首先进行了长时间的搜索并尝试了(正如您所指出的那样,我缺少的技能)我找到的解决方案尽可能好。
【解决方案4】:

你可以使用联合:

typedef union
{
    struct
    {
        uint8_t Byte1;
        uint8_t Byte2;
        uint8_t Byte3;
        uint8_t Byte4;
     };
     float      floatvalue;
}TestT;

TestT   Test;

Test.floatvalue = ......    //complete float
Test.Byte1 = .....          //single Byte to save in EEPROM

【讨论】:

  • 将 4 个字节解释为浮点值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多