在 C++ 中正确地将 `void*` 转换为整数
Properly casting a `void*` to an integer in C++
我正在处理一些使用外部库的代码,您可以在其中通过 void*
值将值传递给回调。
不幸的是,以前编写此代码的人决定通过将整数转换为空指针 ((void*)val
) 来将整数传递给这些回调。
我现在正在清理这个烂摊子,我正在尝试确定 "proper" 将整数 to/from 转换为 void*
的方法。不幸的是,修复 void 指针的 use 在某种程度上超出了我在这里能够做的返工的范围。
现在,我正在执行两次转换以将 from/to 转换为空指针:
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
一起工作,但我正试图摆脱它以解决可维护性和与错误相关的问题,所以我正在尝试这样做 "properly",例如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*
的整数值,并且一旦我有一个整数值,我就可以截断它而不会导致编译器抱怨。
考虑到我不得不通过 void 指针推送数据,这是正确的,甚至是明智的方法吗?
"Is this the correct, or even a sane approach given I'm stuck having to push data through a void pointer?"
好吧,关于 正确 和 正常 这值得商榷,特别是如果你是代码的作者 void*
在界面中。
I think using intptr_t
is the correct intermediate here, since it's guaranteed to be large enough to contain the integral value of the void*, and once I have an integer value I can then truncate it without causing the compiler to complain.
是的,这是与 reinterpret_cast<intptr_t>
一起使用的正确类型,但您需要确定已传入 intptr_t
指针类型,并且地址有效且不会超出范围。
在与 c API 交互时偶然发现这个问题并不少见,它们提供 回调 ,让您传递 user-data,它们将透明地处理,并且永远不会被触及,除了你的入口点 1.
因此,由客户端代码确定 void*
应该如何安全地 重新解释 。
1) 这种情况的典型例子是pthread_create()
函数
您别无选择,只能在此处使用 static 和 reinterpret cast。强制转换为 int 会导致精度损失,这从来都不是理想的情况。始终最好避免显式转换,因为迟早要转换的内容可能会发生变化,届时将不会有编译器警告。但在这种情况下,你别无选择是可以理解的。或者你呢?
您可以将您这边的回调定义更改为 intptr_t 或 long int 而不是 void*,然后它应该可以工作,您将不必进行任何类型转换...
I think using intptr_t
is the correct intermediate here, since it's guaranteed to be large enough to contain the integral value of the void*
, and once I have an integer value I can then truncate it without causing the compiler to complain.
是的,正如您提到的那样,这是正确的中间类型。到现在为止,如果您的实现不提供它,您可能遇到的问题不仅仅是缺少 typedef。
Is this the correct, or even a sane approach given I'm stuck having to push data through a void pointer?
是的,考虑到限制,这很正常。
您可能会考虑检查值是否适合,而不是简单地在调试模式下从 void*
中解压缩它时将其截断,或者甚至使该整数的所有进一步处理使用 intptr
而不是 int
来避免截断。
您还可以考虑通过该参数将指针推送到实际的 int
而不是 int
本身。请注意,这虽然效率较低,但会让您面临终生问题。
根据您的问题,我假设您在某个库中调用一个函数,将其传递给 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);
}
您应该使用哪一个取决于您需要对数据做什么,以及修改数据的能力在将来是否有用。
我正在处理一些使用外部库的代码,您可以在其中通过 void*
值将值传递给回调。
不幸的是,以前编写此代码的人决定通过将整数转换为空指针 ((void*)val
) 来将整数传递给这些回调。
我现在正在清理这个烂摊子,我正在尝试确定 "proper" 将整数 to/from 转换为 void*
的方法。不幸的是,修复 void 指针的 use 在某种程度上超出了我在这里能够做的返工的范围。
现在,我正在执行两次转换以将 from/to 转换为空指针:
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
一起工作,但我正试图摆脱它以解决可维护性和与错误相关的问题,所以我正在尝试这样做 "properly",例如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*
的整数值,并且一旦我有一个整数值,我就可以截断它而不会导致编译器抱怨。
考虑到我不得不通过 void 指针推送数据,这是正确的,甚至是明智的方法吗?
"Is this the correct, or even a sane approach given I'm stuck having to push data through a void pointer?"
好吧,关于 正确 和 正常 这值得商榷,特别是如果你是代码的作者 void*
在界面中。
I think using
intptr_t
is the correct intermediate here, since it's guaranteed to be large enough to contain the integral value of the void*, and once I have an integer value I can then truncate it without causing the compiler to complain.
是的,这是与 reinterpret_cast<intptr_t>
一起使用的正确类型,但您需要确定已传入 intptr_t
指针类型,并且地址有效且不会超出范围。
在与 c API 交互时偶然发现这个问题并不少见,它们提供 回调 ,让您传递 user-data,它们将透明地处理,并且永远不会被触及,除了你的入口点 1.
因此,由客户端代码确定 void*
应该如何安全地 重新解释 。
1) 这种情况的典型例子是pthread_create()
函数
您别无选择,只能在此处使用 static 和 reinterpret cast。强制转换为 int 会导致精度损失,这从来都不是理想的情况。始终最好避免显式转换,因为迟早要转换的内容可能会发生变化,届时将不会有编译器警告。但在这种情况下,你别无选择是可以理解的。或者你呢?
您可以将您这边的回调定义更改为 intptr_t 或 long int 而不是 void*,然后它应该可以工作,您将不必进行任何类型转换...
I think using
intptr_t
is the correct intermediate here, since it's guaranteed to be large enough to contain the integral value of thevoid*
, and once I have an integer value I can then truncate it without causing the compiler to complain.
是的,正如您提到的那样,这是正确的中间类型。到现在为止,如果您的实现不提供它,您可能遇到的问题不仅仅是缺少 typedef。
Is this the correct, or even a sane approach given I'm stuck having to push data through a void pointer?
是的,考虑到限制,这很正常。
您可能会考虑检查值是否适合,而不是简单地在调试模式下从 void*
中解压缩它时将其截断,或者甚至使该整数的所有进一步处理使用 intptr
而不是 int
来避免截断。
您还可以考虑通过该参数将指针推送到实际的 int
而不是 int
本身。请注意,这虽然效率较低,但会让您面临终生问题。
根据您的问题,我假设您在某个库中调用一个函数,将其传递给 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);
}
您应该使用哪一个取决于您需要对数据做什么,以及修改数据的能力在将来是否有用。