C GTK2回调数据丢失(设置为0/垃圾)

C GTK2回调数据丢失(设置为0/垃圾),c,debugging,gtk,gtk2,C,Debugging,Gtk,Gtk2,我正在GTK中制作一个类似OneNote的应用程序,但在实现一些基本功能时遇到了问题。我有一个菜单按钮,可以加载到要处理的文件中,但由于某些原因,GTK在运行回调时没有检索到与回调一起存储的数据。我使用GDB来跟踪问题,似乎每当调用我的任何回调函数时,数据参数始终为零,无论我在将回调连接到信号时将其设置为什么 这里有一些我认为相关的代码片段,但完整的源代码在GitHub repo上 c(主程序逻辑文件。我创建主窗口、需要引用的其他小部件以及保存这些引用的数组。然后继续设置菜单。) menu.c(

我正在GTK中制作一个类似OneNote的应用程序,但在实现一些基本功能时遇到了问题。我有一个菜单按钮,可以加载到要处理的文件中,但由于某些原因,GTK在运行回调时没有检索到与回调一起存储的数据。我使用GDB来跟踪问题,似乎每当调用我的任何回调函数时,数据参数始终为零,无论我在将回调连接到信号时将其设置为什么

这里有一些我认为相关的代码片段,但完整的源代码在GitHub repo上

c(主程序逻辑文件。我创建主窗口、需要引用的其他小部件以及保存这些引用的数组。然后继续设置菜单。)

menu.c(我在这里创建菜单栏并将回调链接到菜单按钮。我使用调试器进行检查,当主窗口和sectionNotebook用作回调数据时,它们的引用似乎仍然有效。)

c(我在这里为各种小部件实现小部件回调例程。) 这就是我似乎有问题的地方

gint fileMenuOpenCallback(GtkWidget *widget, GdkEvent *event, 
gpointer calldata) {
    GtkWidget *openNotebookDialog;
    char *filename;
    GtkWidget **importantWidgets = (GtkWidget**)calldata;

    openNotebookDialog = gtk_file_chooser_dialog_new("Open Notebook...", 
        GTK_WINDOW(importantWidgets[0]), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, 
        GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
        NULL);
    ...
}
我在回调的第三行以及代码中的其他一些地方放了一个断点,并使用gdb查看一些变量的值。下面是我使用gdb时发生的情况:

GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Reading symbols from bin/notekeeper...done.
(gdb) b notekeeper.c:46
Breakpoint 1 at 0x80490f3: file src/notekeeper.c, line 46.
(gdb) b menu.c:37
Breakpoint 2 at 0x804945b: file src/menu.c, line 37.
(gdb) b callbacks.c:38
Breakpoint 3 at 0x8049319: file src/callbacks.c, line 38.
(gdb) run
Starting program: [PROJECT DIRECTORY]/bin/notekeeper 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/i686/cmov/libthread_db.so.1".
Gtk-Message: Failed to load module "canberra-gtk-module"

Breakpoint 1, main (argc=1, argv=0xbffff3f4 "x\365\377\277")
    at src/notekeeper.c:46
46      topWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
(gdb) next
47      g_signal_connect(G_OBJECT(topWindow), "delete_event", 
(gdb) print topWindow
$1 = (GtkWidget *) 0x8072248
(gdb) continue
Continuing.

Breakpoint 2, setupMenu (importantWidgets=0xbffff324) at src/menu.c:37
37      FileMenuItems[0] = gtk_menu_item_new_with_mnemonic("Open");
(gdb) print importantWidgets
$2 = (GtkWidget **) 0xbffff324
(gdb) print importantWidgets[0]
$3 = (GtkWidget *) 0x8072248
(gdb) continue
Continuing.

Breakpoint 3, fileMenuOpenCallback (widget=0x80abc28, event=0xbffff324, 
    calldata=0x14) at src/callbacks.c:38
38      GtkWidget **importantWidgets = (GtkWidget**)calldata;
(gdb) p calldata
$4 = (gpointer) 0x14
(gdb) p (GtkWidget **)calldata
$5 = (GtkWidget **) 0x14
(gdb) p (GtkWidget **)calldata[0]
Attempt to dereference a generic pointer.
(gdb) continue
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x08049329 in fileMenuOpenCallback (widget=0x80abc28, event=0xbffff324, 
    calldata=0x14) at src/callbacks.c:42
42          GTK_WINDOW(importantWidgets[0]), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, 
(gdb) kill
Kill the program being debugged? (y or n) yes
(gdb) 
我们可以在断点1处看到topWindow(这是我试图在回调中使用的值)被设置为实际地址。然后,在断点2处,我们进入了setupMenu函数,在这里我设置了菜单栏,并将信号连接到菜单的回调

之后,应用程序出现在屏幕上,我点击菜单上的打开按钮,使其运行我的回调。这就是断点3停止应用程序的地方。您可以在这里看到,此时我的数据的函数参数是0x14,不再指向我的小部件引用列表。我甚至将它转换回程序中的正确类型,并尝试引用它,但调试器不会这样做。所以,我继续,程序尝试使用这个值,但是当然,它坏了,我因为试图访问一些我不应该访问的内存而得到了一个segfault

我并不太关心崩溃,因为我可以通过将NULL替换为GTK_窗口(importantWidgets[0])来阻止崩溃,GTK_窗口应该是对我的根窗口的引用。我主要关心的是为什么数据参数calldata在本例中设置为0x14。当我将信号连接到回调时,我给它分配了一个完全不同的值,所以我不确定发生了什么。GTK2中是否已弃用或删除此数据参数?或者它运行正常而我用错了。我只是想知道为什么GTK会这样

为了测试我的理论,我甚至向一个其他回调函数添加了一些虚拟数据,该函数只运行gtk_main_quit()。但是当我用GDB调试时,虚拟数据不在那里。它再次被设置为0,或其他一些小数字。因此,这个问题似乎影响了所有的GTK


如果你有任何想法,请让我知道,我是GTK的新手,所以我想知道为什么它看起来像这样不稳定,这是我的错还是GTK中有一个bug。同样,如果您需要仔细查看或自己运行,完整的代码在Github repo中。它应该只需要autoconf、make、C编译器、GTK2(而不是3)和libxml2就可以构建和运行

参见约翰对原始帖子的评论。事实证明,并非所有GTK信号都具有相同的回调函数参数。这个没有GDKEvent参数。谢谢你的帮助

我认为您的
filemenuoppencallback
参数是错误的。GtkMenuItem的信号只有两个参数:GtkMenuItem对象和用户数据。你完全正确!我刚才假设所有信号在回调中都需要相同的参数结构,但似乎不是这样。也许我应该用一下RTFM。谢谢你的帮助!你反应很快。
gint fileMenuOpenCallback(GtkWidget *widget, GdkEvent *event, 
gpointer calldata) {
    GtkWidget *openNotebookDialog;
    char *filename;
    GtkWidget **importantWidgets = (GtkWidget**)calldata;

    openNotebookDialog = gtk_file_chooser_dialog_new("Open Notebook...", 
        GTK_WINDOW(importantWidgets[0]), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, 
        GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
        NULL);
    ...
}
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Reading symbols from bin/notekeeper...done.
(gdb) b notekeeper.c:46
Breakpoint 1 at 0x80490f3: file src/notekeeper.c, line 46.
(gdb) b menu.c:37
Breakpoint 2 at 0x804945b: file src/menu.c, line 37.
(gdb) b callbacks.c:38
Breakpoint 3 at 0x8049319: file src/callbacks.c, line 38.
(gdb) run
Starting program: [PROJECT DIRECTORY]/bin/notekeeper 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/i686/cmov/libthread_db.so.1".
Gtk-Message: Failed to load module "canberra-gtk-module"

Breakpoint 1, main (argc=1, argv=0xbffff3f4 "x\365\377\277")
    at src/notekeeper.c:46
46      topWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
(gdb) next
47      g_signal_connect(G_OBJECT(topWindow), "delete_event", 
(gdb) print topWindow
$1 = (GtkWidget *) 0x8072248
(gdb) continue
Continuing.

Breakpoint 2, setupMenu (importantWidgets=0xbffff324) at src/menu.c:37
37      FileMenuItems[0] = gtk_menu_item_new_with_mnemonic("Open");
(gdb) print importantWidgets
$2 = (GtkWidget **) 0xbffff324
(gdb) print importantWidgets[0]
$3 = (GtkWidget *) 0x8072248
(gdb) continue
Continuing.

Breakpoint 3, fileMenuOpenCallback (widget=0x80abc28, event=0xbffff324, 
    calldata=0x14) at src/callbacks.c:38
38      GtkWidget **importantWidgets = (GtkWidget**)calldata;
(gdb) p calldata
$4 = (gpointer) 0x14
(gdb) p (GtkWidget **)calldata
$5 = (GtkWidget **) 0x14
(gdb) p (GtkWidget **)calldata[0]
Attempt to dereference a generic pointer.
(gdb) continue
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x08049329 in fileMenuOpenCallback (widget=0x80abc28, event=0xbffff324, 
    calldata=0x14) at src/callbacks.c:42
42          GTK_WINDOW(importantWidgets[0]), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, 
(gdb) kill
Kill the program being debugged? (y or n) yes
(gdb)