Void指针转换为C ++和GTK

时间:2010-06-08 16:40:57

标签: c++ c pointers gtk

请参阅此GTK回调函数:

static gboolean callback(GtkWidget *widget, GdkEventButton *event, gpointer *data)
{
    AnyClass *obj = (AnyClass*) data;
    // using obj works
}

(请注意数据上的gpointer *)。然后使用以下信号连接信号:

AnyClass *obj2 = new AnyClass();
gtk_signal_connect(/*GTK params (...)*/, callback, obj2);

看到* AnyClass将被转换为gpointer *(void **)。事实上,这现在正在发挥作用。 GTK文档中的回调原型是“gpointer数据”,而不是代码中显示的“gpointer * data”,我想知道的是:它如何工作?这样安全吗?

2 个答案:

答案 0 :(得分:2)

这并不完全安全,特别是因为在使用c风格的演员表时,你已经从执行从T1 *到void *的static_cast,再到从T1 *到void **的reinterpret_cast。但是,它的工作原理是因为标准保证你可以从T1 *到T2 *(在这种情况下T2 = void *)重新解释,然后再返回以获得你开始时的相同T1 * .... T1 *的IFF对齐要求T2 *是相同的。

换句话说,它适用于大多数实现。来自void *的演员阵容是有保证的,但我不知道对于void **有任何要求。

进行reinterpret_cast总是有点风险。你必须在两侧完全正确地使用T1,如果你弄错了,编译器无法帮助你。例如,如果你从类T5(它是T1的子类)转换,然后在另一侧转换为T1 * ...你可能完全搞砸了。我认为static_cast会解释这个,但是reinterpret_cast不会。它可以正常工作,直到有人因为某种原因在T5上使用多重继承。

通过在隐藏类型中添加*,您无法获得任何收益。你应该考虑不这样做。

注意:我的答案是关于C ++语言。你把你的问题标记为两者,这样你就可以得到两者的答案,而且它们将会非常不同。

答案 1 :(得分:1)

指针本质上是一个数字。指向指针的指针也是一个数字。当你使用强制转换时,你基本上抛弃了任何类型的信息/语义,只要变量大小是兼容的(并且每个指针,包括指针到指针的大小都相同)。

假设您的新AnyClass对象已在0x12345678分配。

AnyClass *obj2 = new AnyClass(); // obj2 = 0x12345678

然后你将它的地址传递给gtk_signal_connect(nb。你应该使用g_signal_connect):

gtk_signal_connect (/* args */, 0x12345678);

然后,调用您的回调,并提供您提供的参数数据:

callback (address_of_widget, address_of_event_structore, 0x12345678); // because you passed 0x12345678 in gtk_signal_connect

现在,因为0x12345678是有效地址,所以可以将其强制转换为有效的AnyClass指针。 data参数可以定义为gpointer************,无关紧要,因为当您将其转换为AnyClass*时,无论如何都会丢弃原始类型信息。