25

static_cast注:原来我错问了;这就是为什么最重要的答案static_cast首先提到的原因。

我有一些带有小端浮点值的二进制文件。我想以独立于机器的方式阅读它们。我的字节交换例程(来自 SDL)对无符号整数类型进行操作。

简单地在整数和浮点数之间进行转换是否安全?

float read_float() {
    // Read in 4 bytes.
    Uint32 val;
    fread( &val, 4, 1, fp );
    // Swap the bytes to little-endian if necessary.
    val = SDL_SwapLE32(val);
    // Return as a float
    return reinterpret_cast<float &>( val );  //XXX Is this safe?
}

我希望这个软件尽可能便携。

4

2 回答 2

37

好吧,static_cast它是“安全的”并且它具有定义的行为,但这可能不是您所需要的。将整数值转换为浮点类型只会尝试在目标浮点类型中表示相同的整数值。即5类型int将变成5.0类型float(假设它可以精确表示)。

您似乎正在做的是在声明为变量float的一块内存中构建值的对象表示。Uint32要产生结果float值,您需要重新解释该内存。这将通过reinterpret_cast

assert(sizeof(float) == sizeof val);
return reinterpret_cast<float &>( val );

或者,如果您愿意,也可以是同一事物的指针版本

assert(sizeof(float) == sizeof val);
return *reinterpret_cast<float *>( &val );

尽管这种类型的双关语不能保证在遵循严格别名语义的编译器中工作。另一种方法是这样做

float f;

assert(sizeof f == sizeof val);
memcpy(&f, &val, sizeof f);

return f;

或者你可以使用著名的 union hack 来实现内存重新解释。这在 C++ 中是正式非法的(未定义行为),这意味着此方法只能用于支持它作为扩展的某些实现

assert(sizeof(float) == sizeof(Uint32));

union {
  Uint32 val; 
  float f;
} u = { val };

return u.f;
于 2012-12-20T23:55:55.083 回答
4

简而言之,这是不正确的。您正在将整数转换为浮点数,编译器当时会将其解释为整数。上面介绍的联合解决方案有效。

另一种与联合做同样事情的方法是使用这个:

return *reinterpret_cast<float*>( &val );

它与上面的联合解决方案同样安全/不安全,我肯定会推荐一个断言来确保 float 与 int 大小相同。

我还要警告说存在不兼容 IEEE-754 或 IEEE-854 的浮点格式(这两个标准具有相同的浮点数格式,老实说,我不完全确定细节差异是什么)。因此,如果您有一台使用不同浮点格式的计算机,它就会崩溃。我不确定是否有任何方法可以检查这一点,除了可能在某处存储一组罐装字节以及浮点中的预期值,然后转换这些值并查看它是否“正确”出现。

于 2012-12-21T00:11:36.943 回答