为什么我的 GTK+ 信号回调中出现分段错误?

Why do I get a segmentation fault in my GTK+ signal callback?

我正在尝试测量 GTK 标签的大小:

#include <gtk/gtk.h>

static void map_event(GtkWidget *window, gpointer lab) {
    g_print( "In the callback..\n" );
    GtkWidget *label = GTK_WIDGET(lab);
    g_print( "Everything is ok..\n" );
}

static void activate (GtkApplication* app, gpointer user_data)
{
    GtkWidget *window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Window1");
    gtk_window_set_default_size (GTK_WINDOW (window), 200, 280);
    GtkWidget *grid = gtk_grid_new ();
    gtk_container_add (GTK_CONTAINER (window), grid);
    GtkWidget *label = gtk_label_new("Hello world!");
    gtk_grid_attach(GTK_GRID (grid), label, 0,0,1,1);
    g_signal_connect (window, "map-event", G_CALLBACK(map_event), label);
    gtk_widget_show_all (window);
}

int main (int argc, char **argv) {
    GtkApplication *app = gtk_application_new (
        "org.gtk.example", G_APPLICATION_FLAGS_NONE );
    g_signal_connect( app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref (app);

    return status;
}

这给出了输出:

In the callback..
Segmentation fault (core dumped)

如果我注释掉这一行:

GtkWidget *label = GTK_WIDGET(lab);

没有分段错误,标签出现,输出为:

In the callback..
Everything is ok..

我在这里错过了什么?

map-event 具有以下签名,因此您缺少 GdkEvent* 参数:

gboolean
user_function (GtkWidget *widget,
               GdkEvent  *event,
               gpointer   user_data)

不幸的是,GTK+是用C写的,所以它缺少类型安全的回调函数,所以很容易犯这样的错误。

您不尊重信号签名。每个信号都与一个预定义的函数原型相关联,您 必须 遵守,否则您只会阅读垃圾。在这里,您只是胡乱编造了回调签名,所以事情不会按预期工作。

信号就像美味的水果送货服务。通过连接到该信号,您签署了一份订阅水果送货服务的合同。水果只有在水果成熟时才会交付。送货员将:

  • 来到你家门前
  • 送你几个水果盒
  • 敲你的门
  • 回到卡车上

合同还规定:

  • 盒子 #1 将包含香蕉
  • 盒子 #2 将包含苹果
  • 盒子 #3 将包含橙子

这些框就像您的回调参数。 map-event 有 3 个参数,因此有 3 个框。

有一天,你听到敲门声。你打开门,看到箱子,打开箱子 #2,然后生气地说 "damn, I said I wanted oranges!"。问题是你在混合苹果和橘子:根据合同,橘子在#3 盒子里,你在#2 盒子里找。

因此请查看您要连接的每个信号的文档。这是编写正确回调的唯一方法。这里您忘记了一个输入参数以及 return 值。在 map-event 的情况下,可以看到 return 值,因为你要去卡车上说你是想继续还是停止交付。