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

Fak*_*ame 6 c++ pointers casting

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

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

我现在正在努力清理这个烂摊子,我正在尝试确定将一个整数转换为/来自a的"正确"方法void*.不幸的是,修复void指针的使用有点超出了我能够在这里做的返工的范围.

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

static_cast<int>(reinterpret_cast<intptr_t>(void_p))
Run Code Online (Sandbox Code Playgroud)

reinterpret_cast<void *>(static_cast<intptr_t>(dat_val))
Run Code Online (Sandbox Code Playgroud)

由于我在64位机器上,直接((int)void_p)转换会导致错误:

error: cast from 'void*' to 'int' loses precision [-fpermissive]
Run Code Online (Sandbox Code Playgroud)

最初的实现确实有效-fpermissive,但我试图摆脱可维护性和与bug相关的问题,所以我试图"正确"地做到这一点,例如c ++强制转换.

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

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

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

Ded*_*tor 6

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

是的,出于您提到的原因,这是正确的中间类型。到现在为止,如果您的实现不提供它,那么您可能会遇到更多的问题,而不仅仅是缺少 typedef。

鉴于我不得不通过空指针推送数据,这是正确的,甚至是一种理智的方法吗?

是的,考虑到限制,它是相当理智的。
您可能会考虑检查值是否合适,而不是在从void*调试模式解包时简单地截断它,或者甚至使用该整数的所有进一步处理intptr而不是int避免截断。

您还可以考虑通过该参数将指针推送到实际int而不是其int本身。请注意,这虽然效率较低,但会让您面临终生问题。


Nic*_*tin 6

根据您的问题,我假设您在某个库中调用一个函数,将其传递给 a void*,并在稍后的某个时间点调用您的一个函数,并将相同的void*.

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

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);
}
Run Code Online (Sandbox Code Playgroud)

您应该使用哪一个取决于您需要对数据做什么,以及修改数据的能力在未来是否有用。