施放到空*并返回Original_Data_Type*

Casting to void* and Back to Original_Data_Type*

本文关键字:Data Type Original 施放 返回      更新时间:2023-10-16

我已经看到并使用了很多次,这是C++,特别是在各种线程实现中。我想知道这样做是否有任何陷阱/问题?当我们投射到 void* 并再次返回时,有什么方法可以遇到错误或未定义的条件吗?如果有这些问题,我们应该如何解决?

谢谢。

这是

完全有效的。以下是标准对它的看法:

§4.10 指针转换

2 "指向 cv T 的指针"类型的右值,其中 T 是一个对象 类型,可以转换为类型为"指向 cv 的指针"的右值 void。"将"指向 cv T 的指针"转换为"指针"的结果 到 cv void "指向存储位置的开头,其中 T 类型的对象驻留,就好像该对象是派生最多的对象一样 类型 T 的对象 (1.8((即,不是基类子对象(。

这意味着您可以将指向类的指针转换为 void 指针。和。。。

§5.2.9 静态投射

10 可以显式使用">指向 cv void 的指针"类型的右值 转换为指向对象类型的指针。指针类型的值 将对象转换为"指向 cv void 的指针"并返回到 原始指针类型将具有其原始值。

这意味着您可以使用 static_cast 将 void 指针转换回原始类指针。

希望对您有所帮助。祝你好运!

我在C++中没有看到太多的选角void*。 这是 C 语言中在 C++ 中积极避免的做法。

转换为void*会消除所有类型安全性。

如果使用 reinterpret_caststatic_cast 从指针类型强制转换为void*,然后再转换回相同的指针类型,则标准实际上可以保证结果是明确定义的

危险在于您可能会将void*投射到错误的类型,因为您不再确定正确的类型是什么。

在C++中,你不需要静态强制转换来进入void*

int main()
{
    CFoo* foo = new CFoo;
    void* dt = foo;
    tfunc(dt); // or tfunc(foo);
    return 0;
}

注意:你对tfunc()的实现非常正确,因为它确实需要强制转换。

我想知道这样做是否有任何陷阱/问题?

在将void*转换回特定类型时,您需要绝对确定,否则,最终会导致未定义的行为和潜在的灾难。一旦使用void *您将失去类型安全性。很难跟踪void *实际指向的类型,无法保证或确定它确实指向要将其类型转换回的类型。

当我们投射到 void* 并再次返回时,有什么方法可以遇到错误或未定义的条件吗?

是的,#1中提到的场景.

如果有这些问题,我们应该如何解决?

完全避免在C++中使用void *,而是使用模板和继承。
在 C 语言中,在某些情况下,您可能绝对需要它,但尽量将其使用保持在最低限度。
底线,
C/C++允许您在脚上射击自己,这取决于您是否这样做。

标准唯一允许的是,给定A* pa(A*)(void*)pA == pA 。一个后果

void* pv = pA;
A* pA2 = (A*)pv;
pA2->anything ...

将与pA->anything ...相同

其他一切都是"未定义的",广告 - 事实上 - 在某种程度上依赖于实现。

根据我的经验,以下是一些已知的陷阱:

  • 考虑A派生形式BpApBA*B*pB=pA使pB指向A的底部。这并不意味着pBpA是同一个地址。因此pB = (B*)(void*)pA实际上可以将其他任何地方指向 A(尽管单个继承对象通常实现共享相同的来源,因此它显然工作正常(
  • 反之亦然:假设pB实际上指向一个ApA = (A*)(void*)pB不一定正确地指向A对象。正确的方法是pA = static_cast<A*>(pB);
  • 如果
  • 以上几点可以与大多数单一继承实现一起使用,则永远不会适用于第一个以外的基数的多个不连续性:考虑class A: public Z, public B { ... };如果Z不为空,给定一个AB子组件将不具有相同的 A 地址。(C++中的多重继承无处不在(
  • 有时事情也取决于平台:(char*)(void*)pI(其中pI指向整数(将与"*pI如果*pI in(-128..+127("不同(仅在小端序机器上(

一般来说,不要假设类型之间的转换只是改变了地址的解释方式

我知道驱动程序等中的很多函数使用void指针将数据返回给调用方,架构大致相同:

int requestSomeData(int kindOfData, void * buffer, int bufferSize);

此函数可以采用不同的数据类型作为参数。他们所做的是使用 bufferSize 作为参数,以避免写入他们不应该写入的内存位置。如果 bufferSize 不匹配或小于应返回的数据,则该函数将返回错误代码。

无论如何:避免使用它们或在编写任何代码之前三思而后行。

这有效吗?

是的,根据标准 § 5.2.9.7 有效

类型为"指向 cv1 void 的指针"的 prvalue 可以转换为类型为"指向 cv2 T 的指针"的 prvalue,其中 T 是对象类型,cv2 与 cv1 具有相同的 cv 限定条件,或比 cv1 具有更高的 cv 限定条件。空指针值将转换为目标类型的空指针值。指向对象的指针类型的值转换为"指向 cv void 的指针"并返回,可能具有不同的 cv 限定,应具有其原始值。[ 示例:

T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
bool b = p1 == p2; // b will have the value true.