You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在GTK4的C语言代码中如何正确向g_signal_connect传递结构体?

问题分析与解决

核心原因

你遇到的问题大概率是传入的结构体是局部栈变量:当创建结构体的函数执行完毕后,栈上的内存会被系统释放或覆盖,等按钮触发回调时,你访问的已经是无效内存,所以输出了随机值(这里表现为0)。

解决方案

方案1:动态分配结构体内存(推荐)

用g_malloc()(GTK推荐的内存分配函数)或标准C的malloc()在堆上分配内存,确保回调触发时内存依然有效。记得在窗口销毁时释放内存,避免泄漏。

示例代码:

#include <gtk/gtk.h>

typedef struct {
    int x;
    int y;
} Location;

void print_location(GtkWidget *widget, gpointer data) {
    Location *loc = (Location *)data;
    g_print("x: %d, y: %d\n", loc->x, loc->y);
}

// 窗口销毁时释放结构体内存
void on_window_destroy(GtkWidget *widget, gpointer data) {
    g_free(data);
    gtk_main_quit();
}

int main(int argc, char *argv[]) {
    gtk_init(&argc, &argv);

    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    GtkWidget *button = gtk_button_new_with_label("Print Location");

    // 动态分配结构体内存
    Location *loc = g_malloc(sizeof(Location));
    loc->x = 1;
    loc->y = 5;

    // 绑定按钮点击信号,传入结构体地址
    g_signal_connect(button, "clicked", G_CALLBACK(print_location), loc);
    // 绑定窗口销毁信号,用于释放内存
    g_signal_connect(window, "destroy", G_CALLBACK(on_window_destroy), loc);

    gtk_container_add(GTK_CONTAINER(window), button);
    gtk_widget_show_all(window);

    gtk_main();
    return 0;
}

方案2:使用全局变量(适合快速测试,不推荐大型项目)

把结构体定义为全局变量,这样内存不会随函数执行结束被释放:

#include <gtk/gtk.h>

typedef struct {
    int x;
    int y;
} Location;

// 全局结构体,内存生命周期贯穿整个程序
Location loc;

void print_location(GtkWidget *widget, gpointer data) {
    Location *ptr = (Location *)data;
    g_print("x: %d, y: %d\n", ptr->x, ptr->y);
}

int main(int argc, char *argv[]) {
    gtk_init(&argc, &argv);

    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    GtkWidget *button = gtk_button_new_with_label("Print Location");

    loc.x = 1;
    loc.y = 5;

    g_signal_connect(button, "clicked", G_CALLBACK(print_location), &loc);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_container_add(GTK_CONTAINER(window), button);
    gtk_widget_show_all(window);

    gtk_main();
    return 0;
}

关键注意点

  • 绝对不要把局部栈变量的地址传给g_signal_connect的data参数,除非你能保证回调触发时该变量所在的函数还在运行。
  • 用动态内存时,必须在合适的时机(比如窗口销毁)释放内存,否则会造成内存泄漏。
  • 回调函数里要正确将gpointer转换为你的结构体指针类型,类型不匹配也会导致错误输出。

内容的提问来源于stack exchange,提问作者Troglobyte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 05:03:21