正确地将`void *`转换为C ++中的整数

时间:2015-06-10 22:55:22

标签: c++ pointers casting

我正在处理一些使用外部库的代码,您可以在其中通过void*值将值传递给回调。

不幸的是,前一个处理此代码的人决定通过将整数转换为void指针((void*)val)来将整数传递给这些回调。

我现在正在努力清理这个烂摊子,我正在努力确定"正确的"从void*转换整数的方法。不幸的是,修复void指针的 use 有点超出了我能够在这里做的返工的范围。

现在,我正在进行两次转换,以便从/转换为void指针:

static_cast<int>(reinterpret_cast<intptr_t>(void_p))

reinterpret_cast<void *>(static_cast<intptr_t>(dat_val))

由于我在64位计算机上,直接投射((int)void_p)会导致错误:

error: cast from 'void*' to 'int' loses precision [-fpermissive]

最初的实现 -fpermissive一起使用,但我试图摆脱可维护性和与bug相关的问题,所以我试图这样做&#34;正确&#34;,例如c ++演员。

直接转换为int(static_cast<int>(void_p))失败(error: invalid static_cast from type 'void*' to type 'int')。我对reinterpret_cast的理解是,它基本上只是让编译器将有问题的值的地址视为强制转换数据类型而不实际发出任何机器代码,因此直接将int转换为void*是一个坏主意,因为void*大于int(分别为4/8字节)。

认为使用intptr_t是正确的中间人,因为它保证足够大以包含void*的整数值,并且一次我有一个整数值,然后我可以截断它而不会导致编译器抱怨。

这是正确的,甚至是理智的方法,因为我不得不通过无效指针推送数据?

4 个答案:

答案 0 :(得分:3)

  

我认为在这里使用intptr_t是正确的中间体,因为它保证足够大以包含void*的整数值,并且一旦我有一个整数值,我就可以截断它导致编译器抱怨。

是的,因为你提到的是适当的中间类型。到目前为止,如果您的实现没有提供它,您可能遇到的问题多于缺少的typedef。

  

这是正确的,甚至是理智的方法,因为我不得不通过无效指针推送数据?

是的,鉴于有限制,这是非常理智的 您可以考虑检查值拟合,而不是简单地在调试模式下从void*解压缩它,或者甚至使用intptr而不是int对该整数进行所有进一步处理避免截断。

您也可以考虑通过该参数将指针推送到实际int而不是int本身。请注意,效率会降低,并且会让您终生难忘。

答案 1 :(得分:2)

根据你的问题,我假设你在某个库中调用一个函数,并将它传递给void*,并且稍后会在某个时间点调用你的一个函数,并将它传递给void* { 1}}。

基本上有两种方法可以做到这一点;第一种是通过显式转换,正如您在当前代码中所示。

另一个,Deduplicator提到的,效率稍低,但允许你保持对数据的控制,并可能在你调用库函数和调用你的回调函数之间修改它。这可以通过类似于此的代码来实现:

void callbackFunction(void* dataPtr){
    int data = *(int*)dataPtr;
    /* DO SOMETHING WITH data */
    delete dataPtr;
}
void callLibraryFunction(int dataToPass){
    int* ptrToPass = new int(dataToPass);
    libraryFunction(ptrToPass,callbackFunction);
}

您应该使用哪一个取决于您需要对数据执行的操作,以及将来修改数据的能力是否有用。

答案 2 :(得分:1)

  

“这是正确的,甚至是理智的方法,因为我不得不通过无效指针推送数据?”

好吧,关于正确的 sane ,这是值得商榷的,特别是如果你是接口中void*的代码的作者。

  

我认为在这里使用intptr_t是正确的中间体,因为它保证足够大以包含void *的整数值,并且一旦我有一个整数值,我就可以截断它而不会导致编译器抱怨。

是的,这是与reinterpret_cast<intptr_t>一起使用的正确类型,但您需要确保已传入intptr_t指针类型,且地址有效并且不会超出范围。

API进行交互并且这些提供回调,允许您传入用户数据时,偶然发现这个问题并不是很少见em>,除了你的入口点 1 之外,它们将由它们透明地处理,并且永远不会被触及。

因此,客户端代码可以确定void*应如何安全地 重新解释

1) 这种情况的经典例子是pthread_create()函数

答案 3 :(得分:0)

你别无选择,只能在这里使用静态和重新解释。转换为int将导致精度损失,这绝不是理想的。总是最好避免显式地转换,因为迟来的内容可以改变,然后就不会有编译器警告。但在这种情况下你可以理解别无选择。或者你呢?

您可以将侧面的回调定义更改为intptr_t或long int而不是void *,然后它应该可以工作,您不必进行任何类型转换...