4

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

谢谢你。

4

7 回答 7

16

这是完全有效的。以下是标准对它的评价:

§4.10 指针转换

2 “指向cv T的指针”类型的右值,其中T是对象类型,可以转换为“指向cv void的指针”类型的右值。将“指向cv的指针”转换为“指向cv 的指针”的结果指向类型对象所在的存储位置的开始,就好像该对象是最派生的类型对象 (1.8) (即不是基类子对象)。T voidTT

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

§5.2.9 静态演员表

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

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

希望能帮助到你。祝你好运!

于 2013-09-21T05:31:57.620 回答
6

在 C++ 中,您不需要静态强制转换即可 void*

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

    return 0;
}

注意:您的实现tfunc()是非常正确的,因为它确实需要演员表。

于 2014-09-11T13:00:02.367 回答
5

我在 C++ 中没有看到太多的转换。void*这是 C 中的一种实践,在 C++ 中被积极避免。

转换为void*删除所有类型的安全性。

如果您使用reinterpret_castorstatic_cast将指针类型转换为相同的void*指针类型并返回到相同的指针类型,则标准实际上保证了结果将是明确定义的

危险在于您可能将 avoid*转换为错误的类型,因为您不再确定正确的类型是什么。

于 2012-09-05T06:12:30.990 回答
3

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

在将 back 转换为特定类型时,您需要绝对确定void*,如果不这样做,您最终会遇到未定义的行为和潜在的灾难。一旦你使用void *你就会失去类型安全性。很难跟踪 avoid *实际指向的类型,没有办法保证或确定它确实指向你要将它类型转换回的类型。

当我们强制转换为 void* 并再次返回时,有什么方法可以让我们遇到错误或未定义的情况?

是的,中提到的场景#1

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

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

于 2012-09-05T06:06:47.763 回答
2

标准授予的唯一一件事是,给定A* pa, (A*)(void*)pA == pA。一个后果

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

将与pA->anything ...

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

根据我的经验,这里有一些已知的陷阱:

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

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

于 2012-09-05T07:26:14.540 回答
1

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

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

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

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

于 2012-09-05T06:10:34.897 回答
1

这是有效的吗?

是的,根据标准 § 5.2.9.7 它是有效的

“指向 cv1 void 的指针”类型的纯右值可以转换为“指向 cv2 T 的指针”类型的纯右值,其中 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.
于 2013-09-21T05:30:38.260 回答