GSList传递给Glib宏(例如G_OBJECT_TYPE_NAME()GTK_IS_WIDGET()等)会导致分段错误。

这是一个问题,因为我的程序必须处理GObjects列表,并且无法测试GSList...。此外,仅对GSList执行测试会导致段错误,因此它甚至无法到达else块。

有人知道为什么会这样吗?

#include <gtk/gtk.h>
int main (int argc, char *argv[])
{
    g_type_init();
    GtkWidget * widget;

    GSList * gslist = NULL;
    gslist = g_slist_append(gslist,widget);

    GHashTable * table = g_hash_table_new(NULL,NULL);
    g_hash_table_insert(table, (gchar *) "key", (char *) "value");
    g_hash_table_insert(table, (gchar *) "slist", gslist);

    if(GTK_IS_WIDGET(g_hash_table_lookup(table,"slist"))){}
}


段错误发生在g_type_check_instance_is_a () from /usr/lib/libgobject-2.0.so.0中,删除GTK_IS_WIDGET程序运行正常。

最佳答案

GSList不是GObject,即它不提供类型检查宏运行所必需的机制,这会导致您观察到崩溃。如果确实需要此类功能,则可能需要为列表创建包装器(基于GObject)。

不幸的是,您无法测试哈希表中的值类型。 GObject和GTK使用的类型检查宏实际上需要所指向的值的专用支持,即,您必须肯定地知道该值是某种东西,它在使用GObject机器之前就已经使用了首先是宏。如果将结果应用于除GObject以外的任何类型的指针,则结果是不确定的,并且经常会导致崩溃。

请注意,顺便说一句,字符串值(char*)和其他值也会出现此问题。 (为什么将"value"强制转换为char*?)

如果确实需要使用示例中所述的通用哈希表,则必须创建某种包装。直接从GObject派生它或尝试一些最小的方法

typedef struct {
     int type_code;
     union {
         int ival;
         char* str;
         GObject* obj;
         GSList* list;
     } value;
} Cell;

typedef enum {
     INTEGER, STRING, OBJECT, LIST
} CellType;

Cell*
allocate_int_cell(int value)
{
    ...
}


不幸的是,事情要比这复杂得多,因为当从哈希表中删除值(或者哈希表本身已被破坏)时,您还必须管理值的破坏。

10-08 20:02