代码之家  ›  专栏  ›  技术社区  ›  detly

从字节内联重新组装浮点

  •  5
  • detly  · 技术社区  · 14 年前

    我正在与Hitech Picc32合作开发pic32mx系列微处理器,但我认为这个问题对于任何在C语言中了解的人来说都足够普遍(这几乎相当于c90,sizeof(int)=sizeof(long)=sizeof(float)=4。)

    假设我读了一个4字节的数据字,它表示 float . 我可以用以下方法将其快速转换为实际的浮点值:

    #define FLOAT_FROM_WORD(WORD_VALUE) (*((float*) &(WORD_VALUE)))
    

    但这只对lvalues有效。例如,我不能在函数返回值上使用它,例如:

    FLOAT_FROM_WORD(eeprom_read_word(addr));
    

    有没有一个简短而甜蜜的方法来进行内联,即没有函数调用或临时变量?老实说,我没有太多的理由避免函数调用或额外的var,但这让我很烦。一定是我找不到的。

    补充: 我没意识到 WORD 实际上是一个常见的typedef。我已经更改了宏参数的名称以避免混淆。

    5 回复  |  直到 14 年前
        1
  •  8
  •   R Samuel Klatchko    14 年前

    你可以用另一种方法来处理返回值。

    float fl;
    *(int*)&fl = eeprom_read_word(addr);
    

    #define WORD_TO_FLOAT(f)  (*(int*)&(f))
    
    WORD_TO_FLOAT(fl) = eeprom_read_word(addr);
    

    或者如R Samuel Klatchko建议的那样

    #define  ASTYPE(type, val) (*(type*)&(val))
    ASTYPE(WORD,fl) = eeprom_read_word(addr);
    
        2
  •  3
  •   Chris Lutz    14 年前

    如果这是GCC,您可以这样做:

    #define atob(original, newtype) \
      (((union { typeof(original) i; newtype j })(original)).k)
    

    真的。丑陋的但是用法很好:

    int i = 0xdeadbeef;
    float f = atob(i, float);
    

    我打赌你的编译器也不支持 typeof 操作员或 union 强制转换gcc可以这样做,因为这两种行为都不是标准行为,但是编译器可以这样做的可能性很小。 联盟 铸造,这是你的答案。修改为不使用 类型 :

    #define atob(original, origtype newtype) \
      (((union { origtype i; newtype j })(original)).k)
    
    int i = 0xdeadbeef;
    float f = atob(i, int, float);
    

    当然,这忽略了当您使用两种不同大小的类型时会发生什么问题,但更接近于“您想要什么”,即返回值的简单宏过滤器,而不是接受额外参数。这个版本采用的额外参数只是为了通用性。

    如果编译器不支持 联盟 铸造,这是一个整洁但不可移植的技巧,然后没有办法做到这一点的“方式你想要它”,而其他的答案已经得到。

        3
  •  1
  •   matt    14 年前

    如果使用常量引用,则可以获取临时值的地址:

    FLOAT_FROM_WORD(w) (*(float*)&(const WORD &)(w))
    

    但这在C中不起作用:(

    (C没有参考资料的权利吗?在Visual C++中工作

    正如其他人所说,无论是内联函数还是定义中的临时函数,编译器都会对其进行优化。

        4
  •  0
  •   John Knoeller    14 年前

    不是真正的答案,更多的是建议。你的float-from-word宏使用起来更自然,如果没有的话更灵活;最后

    #define FLOAT_FROM_WORD(w) (*(float*)&(w))
    
    fl = FLOAT_FROM_WORD(wd);
    
        5
  •  0
  •   Roger Pate    14 年前

    在您的具体情况下,这可能是不可能的,但是升级到C99编译器也可以解决您的问题。

    C99具有内联函数,在参数和返回值方面与普通函数类似,但在这种情况下效率会得到提高,而宏没有任何缺点。