Как передать несколько переменных в виде данных с помощью сигналов gtk

У меня есть небольшая программа, в которой функция обратного вызова сигнала gtk требует 2 или 3 переменных.

Я не хочу делать эти глобальные переменные (вся цель проекта должна быть аккуратной и аккуратной), и я не хочу создавать целую структуру, чтобы я мог отправлять виджет и скомпилированное регулярное выражение функция.

Насколько я видел, g_signal_connect допускает только одну переменную данных.

Может ли самый эффективный способ сделать это, возможно, быть массивом указателей void для двух объектов? Что-то вроде этого?

void * data[2];
data[0] = widget;
data[1] = compiledregex;
g_signal_connect(save,"clicked",G_CALLBACK(callbackfunction),data);

Ответ 1

Конечно, вы можете использовать массивы указателей void, но если вы хотите передавать значения с разными типами (особенно значения, тип которых длиннее sizeof(void *)), вы не можете использовать массивы. Для этого вы почти наверняка захотите обернуть их в структуру и передать адрес структуры в качестве параметра данных.

Пример:

struct my_struct *data = malloc(sizeof(*data));
data->field_one = value_one;
data->field_two = value_two; /* etc. */

g_signal_connect(save, "clicked", callback, data);

Конечно, не забудьте free(data) в функции обратного вызова (при условии, что он используется для одного использования).

Изменить: как вам нужен пример с void **, вот вы (это уродливо, и я не рекомендую вам использовать это - либо потому, что выделение одноэлементного массива для примитивных типов тратит впустую вашу съемку или из-за того, что литье не указателя на void * является плохой практикой...):

void **data = malloc(sizeof(data[0]) * n_elements);

type1 *element1_ptr = malloc(sizeof(first_item));
*element1_ptr = first_item;
data[0] = element1_ptr;

/* etc. */

Чтобы освободить их:

int i;
for (i = 0; i < n_elements; i++)
    free(data[i]);

free(data);

Ответ 2

Вы можете использовать g_object_set_data() и g_object_get_data(). Сначала задайте данные:

g_object_set_data(G_OBJECT(my_edit), "my_label", my_label);
g_object_set_data(G_OBJECT(my_edit), "age", GINT_TO_POINTER(age));

а в обратном вызове вы можете получить такие данные:

gint age = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "age"));
GtkWidget *my_label = g_object_get_data(G_OBJECT(widget), "my_label");

Ответ 3

Развернув ответ H2CO3, вы также можете установить данные (и я настоятельно рекомендую использовать структуру, кстати), чтобы автоматически освободиться при отключении обработчика сигнала:

g_signal_connect_data(save, "clicked", callback, data, (GClosureNotify)free, 0);