Issue
I am working on one small project in C using GTK4 and Miniaudio. I need to pass some arguments through g_signal_connect() to several widgets. Since I am new to GTK, I tried to experiment on a basic GTK example (hello-world-gtk example) on GTK's Getting started. But, when I pass any callback argument through g_signal_connect() and I get unexpected values.
Here is the example of modified hello-world-gtk code:
#include <stdio.h>
#include <gtk/gtk.h>
void hello(GtkWidget *widget, void *data) {
printf("pointer in hello(): %p\n", data);
printf("data value: %d\n", *(int*)data);
}
void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button;
int abc = 5;
void *ptr = &abc;
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Window");
gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
button = gtk_button_new_with_label("Hello World");
printf("pointer in activate(): %p\n", ptr);
printf("abc value: %d\n", *(int*)ptr);
// Problem occurs here.
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(hello), ptr);
gtk_window_set_child(GTK_WINDOW(window), button);
gtk_window_present(GTK_WINDOW(window));
}
int main(int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new("org.gtk.example", G_APPLICATION_REPLACE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
It is compiled with gcc $(pkg-config --cflags gtk4) -o hello-world-gtk hello-world-gtk.c $(pkg-config --libs gtk4)
command.
Terminal output is:
pointer in activate(): 0x7fff5f4c8124
abc value: 5
pointer in hello(): 0x7fff5f4c8124
data value: 0
pointer in hello(): 0x7fff5f4c8124
data value: 0
On initialization first two lines in terminal are printed and on every button click new 2 lines are printed out (the "pointer in hello():..." and "data value:...").
I expected, as probably guessed, passed pointer's value to be printed, not 0 everytime, or:
pointer in activate(): 0x7fff5f4c8124
abc value: 5
pointer in hello(): 0x7fff5f4c8124
data value: 5
pointer in hello(): 0x7fff5f4c8124
data value: 5
I have tried googling how others use the function g_signal_connect()
, syntax is very similar, but they get expected values (like here, created my small code demo to see if I understant void* and callbacks in C, and yet I get expected values in that demo.
The demo:
#include <stdio.h>
void doing_things(int (*fx)(int), void *param) {
int x = *(int*)param;
printf("Applied function: %d\n", fx(x));
}
int square(int value) {
return value * value;
}
int main() {
int my_val = 5;
int (*my_square)(int) = square;
void *my_pointer = &my_val;
doing_things(my_square, my_pointer);
return 0;
}
Demo's output:
Applied function: 25
I've tried changing types of data
and typecasting to different types (gpointer
is basically void*
), and no success.
I have an idea to make callback parameters extern
, but it is considered a back practice how much I know.
If you know how to fix this problem, I would really appreciate it!
Thanks in advance.
Solution
int abc = 5;
This variable is local to the activate()
function and the pointer you provide to g_signal_connect
...
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(hello), ptr);
... will be dangling as soon as activate()
returns. Dereferencing the pointer inside hello()
therefore has undefined behavior.
A simple fix would be to make it static
to make the variable survive until the end of program execution:
static int abc = 5;
Answered By - Ted Lyngmo Answer Checked By - Mary Flores (WPSolving Volunteer)