以下代码可能出错的地方——以及编译时间要求

What can go wrong in following code - and compile time requirements?

本文关键字:编译 时间 代码 出错      更新时间:2023-10-16

首先让我说我知道下面的代码将被认为是"坏的"实践。但是我受环境的限制有一点点:

在动态库中,我希望使用"指针"(指向类)-然而,将使用此dll的程序只能传递&获得双打。所以我需要"适合"指针在双精度。下面的代码试图实现这一点,我希望在64位环境中工作:

EXPORT double InitializeClass() {
    SampleClass* pNewObj = new SampleClass;
    double ret;
    unsigned long long tlong(reinterpret_cast<unsigned long long>(pNewObj));
    memcpy(&ret, &tlong, sizeof(tlong));
    return ret;
}
EXPORT double DeleteClass(double i) {
    unsigned long long tlong;
    memcpy(&tlong, &i, sizeof(i));
    SampleClass* ind = reinterpret_cast<SampleClass* >(tlong);
    delete ind;
    return 0;
}

现在我再一次意识到我使用矢量可能会更好;将指针存储在vector中。然而,我真的希望使用指针(作为替代方案)来做到这一点。所以谁能告诉我可能的失败/更好的版本?

明显的失败是if double &Unsigned long和Unsigned long在大小上不相同(或者指针长度大于64位)。有没有在编译时检查这个的方法?-并给出一个编译错误,以防大小不一样?

理论上,至少,一个64位的指针,类型双关到64位的IEEEdouble,可能导致捕获NaN,而NaN又会捕获。在练习,这可能不是问题;我试图诱捕NaN除了被人忽视,真正去做点别的已经不是很好了成功。

另一个可能的问题是这些值可能没有规范化(事实上,很可能不会)。硬件做了什么非规范化值取决于:它可以直接传递它们透明地、静默地规范化它们(改变"指针"),或触发某种运行时错误。

还有混叠的问题。通过类访问指针具有double类型的左值是未定义的行为,并且有许多编译器在优化时会利用这一点,假设通过double*double&引用的更改不会影响任何一个指针(并在写入指针之前移动指针的加载)对象修改后不重新加载指针双)。

实际上,如果你在英特尔环境中工作,我认为所有"64位"指针的上16位实际上是0。这就是指数为IEEE双精度,指数为0是渐进的下流,它不会捕获(至少在默认模式下),并且不会是变化。因此,您的代码实际上可能看起来可以工作,只要

assert(sizeof(SampleClass*) <= sizeof(unsigned long long));
assert(sizeof(unsigned long long) <= sizeof(double));

我想说您必须在64位和32位上测试它以确保它工作。假设它在64位系统中确实有不同的行为,那么你可以使用这种格式来解决问题(因为你已经提到你正在使用VS2010):

EXPORT double InitializeClass64() {
    // Assert the pointer-size is the same as the data-type being used
    assert(sizeof(void*) == sizeof(double));
    // 64-bit specific code
    return ret;
}
EXPORT double DeleteClass64(double i) {
    // Assert the pointer-size is the same as the data-type being used
    assert(sizeof(void*) == sizeof(double));
    // 64-bit specific code
    return 0;
}
EXPORT double InitializeClass32() {
    // Assert the pointer-size is the same as the data-type being used
    assert(sizeof(void*) == sizeof(double));
    // 32-bit specific code
    return ret;
}
EXPORT double DeleteClass32(double i) {
    // Assert the pointer-size is the same as the data-type being used
    assert(sizeof(void*) == sizeof(double));
    // 32-bit specific code
    return 0;
}

#if defined(_M_X64) || defined(_M_IA64)
// If it's 64-bit
#    define InitializeClass InitializeClass64
#    define DeleteClass DeleteClass64
#else
// If it's 32-bit
#    define InitializeClass InitializeClass32
#    define DeleteClass DeleteClass32
#endif // _M_X64 || _M_IA64