4

我有一个无符号长整数值,它表示使用 IEEE-754 格式的浮点数。在 C++ 中将其打印为浮点数的最快方法是什么?

我知道一种方法,但我想知道 C++ 中是否有一个更好的方便实用程序。

我知道的方式示例是:

union
{
    unsigned long ul;
    float f;
} u;

u.ul = 1084227584; // in HEX, this is 0x40A00000

cout << "float value is: " << u.f << endl;

(这会打印出 "float value is: 5" )

4

5 回答 5

7

您建议的联合方法是大多数人会采取的通常路线。但是,在 C/C++ 中,从联合中读取与最近编写的成员不同的成员在技术上是未定义的行为。尽管如此,它在几乎所有编译器中都得到了很好的支持。

正如Jon Skeet 所建议的那样,强制转换指针是一个坏主意——这违反了C 的严格别名规则。激进的优化编译器会为此生成不正确的代码,因为它假定类型的指针unsigned long *并且float *永远不会相互别名。

就标准合规性而言(即不调用未定义的行为),最正确的方法是通过 a 进行强制转换char*,因为严格的别名规则允许指char*针对任何其他类型的指针进行别名:

unsigned long ul = 0x40A00000;
float f;
char *pul = (char *)&ul;  // ok, char* can alias any type
char *pf = (char *)&f;    // ok, char* can alias any type
memcpy(pf, pul, sizeof(float));

虽然老实说,我只会使用联合方法。从上面的 cellperformance.com 链接:

这是一个非常常见的习惯用法,并且得到所有主要编译器的良好支持。实际上,以任何顺序对工会的任何成员进行读写都是可以接受的做法。

于 2009-12-06T20:42:34.710 回答
3

编辑:我以前认为这“很讨厌”,但事实证明它比我想象的要糟糕 - 有关详细信息,请参阅评论。我不会推荐这种方法,但我把它留在这里是为了记录这种可能性(以及警告!)


您可以使用指针:

long ul = 1084227584;
float* fp = (float*) &ul;
float f = *fp;

(这可以浓缩成一行,但我认为不这样做更清楚。)

基本上与您的工会相同......并且同样狡猾,除非您确定所涉及类型的大小。

如果您的平台支持它们,您可能应该为整数和浮点类型使用特定于大小的类型名称。

于 2009-12-06T20:17:42.490 回答
3

它仅适用于 32 位机器或 sizeof(long) == sizeof(float) 的机器。在现代机器上,您可能想要使用 int 来代替......如果您正在执行此技巧,您真的必须小心。

于 2009-12-06T20:20:54.190 回答
3

我和 Jon Skeet 有同样的想法,但他打败了我。但是,我会比他做得更简洁一些。

cout << "float value is: " << *((float *) &ulValue)) << endl;

您得到一个指向 unsigned long 的指针,然后将其重新解释为指向 float 的指针,然后取消引用指向 float 的指针会产生 float 值。

由于您在 C++ 中执行此操作,因此使用 reinterpret_cast 而不是旧的 C 样式转换更清楚。

cout << "float value is: " << *(reinterpret_cast<float *>(&ulValue)) << endl;
于 2009-12-06T20:24:44.180 回答
1

swegi 有正确的方向,但错过了一个字符。正确的方法是

long l = 1084227584L
float f = reinterpret_cast<float&>(l);
于 2009-12-07T11:14:25.600 回答