void* 字面上是浮点型,如何进行类型转换?

9
我在我的C++应用程序中使用了这个C库,其中一个函数返回一个void*。虽然我不是很精通纯C,但听说void*可以转换为几乎任何其他类型的指针。我也知道我期望从这个函数中得到一个float。
因此,我将void*强制转换为float*并解引用float*,结果崩溃了。太糟糕了!我调试代码,在gdb中让它评估(float)voidPtr,值正是我所期望和需要的!
但是,请注意,在编译时不可能做到这一点。如果我写了float number = (float)voidPtr;,它就无法编译,这是可以理解的。
那么现在问题来了,我该如何从这个可恶的void*中获取我的float?
编辑:感谢H2CO3,问题已经解决,但我看到有很多答案和评论出现和消失,他们不相信我可以在gdb中执行(float)voidPtr。下面是截图。

2
当然,更好的解决方案是一开始就不要陷入这种情况。 - user395760
3
@delnan,所以OP应该放弃一整个库,因为它使用了空指针吗? - Corey Ogburn
1
@CoreyOgburn 不,我说的是将非指针解释为void指针。void *在某些情况下是完全可以的,但在OP的情况下,某个人出了问题。也许OP使用库的方式不对。 - user395760
1
也许这个函数可以根据调用方式返回指针或实际值。如果没有看到库,我们就无法做出判断。 - James M
2个回答

17

尝试使用指针:

void *theValueAsVoidPtr = // whatever

float flt = *(float *)&theValueAsVoidPtr;

9
请注意,这假定 sizeof(float) == sizeof(void *),但这可能不是真实情况,在这种情况下,将会产生未定义行为。 - user529758
2
这个有效,我漏掉了额外的&。现在不太确定为什么会发生这种情况,但它有效。谢谢。 - xNidhogg
2
@xNidhogg 解释:指针的类型安全性比非指针要弱。您无法将 void * 强制转换为 float,但可以将 void ** 强制转换为 float *。现在,当您这样做并取消引用 theValueAsVoidPtr 变量的地址时,您会获得该变量的内容,只是以另一种类型呈现 - 这称为类型游戏。请参见标有“邪恶浮点位级黑客”的行 - user529758
这段代码在许多编译器上可以工作,但违反了类型别名规则。 - zwol

9

如果我理解正确,你的库在一个声明类型为void *的变量中返回一个浮点数。最安全的方法是使用union将其取回:

#include <assert.h>
static_assert(sizeof(float) == sizeof(void *));

union extract_float {
    float vf;
    void * vp;
};

float foo(...)
{
    union extract_float ef;
    ef.vp = problematic_library_call(...);
    return ef.vf;
}

与接受答案的方法不同,此方法不会触发未定义行为。

1
“最安全的方法是使用union将其取回…” - 不在C++中。访问非活动联合成员是未定义行为。我认为最安全的方法是使用memcpy - jww
@jww 这是 C++ 标准中的一个错误,应该在十年前就修复了。任何没有实现 C99+勘误语义的联合的 C++ 编译器也是有缺陷的。 - zwol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接