以下代码可能出错:编译时间要求?

时间:2011-11-14 10:39:54

标签: c++ pointers

首先让我说我知道下面的代码会被认为是“坏”的做法..但是我受到环境的限制“一点点”:

在动态库中我希望使用“指针”(指向类) - 但是使用此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;
}

现在我又一次意识到我可能会更好地使用矢量&amp;将指针存储在向量内。但是我真的希望使用指针(作为替代)来做到这一点。那么有谁可以告诉我可能的失败/更好的版本?

明显的失败是如果双重&amp; unsigned long long的大小不同(或指针长度超过64位)。有没有一种方法可以在编译时检查这个? - 如果大小不一样,给出编译错误?

3 个答案:

答案 0 :(得分:2)

理论上,至少是一个64位指针,类型被削减为64位IEEE 加倍,可能导致陷阱NaN,这反过来陷阱。在 练习,这可能不是问题;我试图捕获NaN 实际做一些不被忽视的事情并非如此 成功的。

另一个可能的问题是值可能未标准化 (事实上​​,可能不会)。硬件的功能 非标准化值取决于:它可以直接传递它们 透明地,默默地将它们标准化(改变它的值) “指针”),或触发某种运行时错误。

还存在别名问题。通过一个访问指针 类型为double的左值是未定义的行为,很多 假设,编译器在优化时会利用这一点 通过double*double&引用进行的更改不会影响任何内容 指针(并在写入之前移动指针的负载) 修改后的双重或不重新加载指针 双)。

在实践中,如果您在英特尔环境中工作,我想全部 “64位”指针实际上将具有高16位0.这就是位置 指数居于IEEE双精度,指数为0是渐进的 下溢,不会陷阱(至少在默认模式下),也不会 变化。所以你的代码实际上似乎可以工作,只要 编译器没有太多优化。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

我会说你必须在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