Почему указатель данных обратного вызова сигнала указывает на нежелательное значение при срабатывании обратного вызова? - PullRequest
0 голосов
/ 26 февраля 2012

Хорошо, я пишу метод, который создает целую панель, содержащую ее содержимое, и добавляет ее в форму. Панели хранятся в массиве.

Вот основная идея.

void vscale1Event(GtkWidget *widget, int *vscale_id)
{
    int value = gtk_range_get_value(GTK_RANGE(vscale_struct[*vscale_id]->vscale1)); 
    do stuff with this value; 
}


void add_vscale_panel(int vscale_id)
{
    vscale_struct[vscale_id]->vscale1 = ..... ;
    vscale_struct[vscale_id]->vscale2 = ..... ;
    add buttons to form; 

    gtk_signal_connect(GTK_OBJECT(vscale_struct[button_id]), "value_changed", (GtkSignalFunc)vscale1Event, &vscale_id); 
    gtk_signal_connect(GTK_OBJECT(vscale_struct[button_id]), "value_changed", (GtkSignalFunc)vscale2Event, &vscale_id);
}

int main()
{
    for (i = 0; i<n; i++)
    {
        add_vscale_panel(i); 
    }
}

Проблема, с которой я сталкиваюсь, заключается в том, что & vscale_id, который я передаю, позже становится ненужным (его значение равно числу мусора около 32000), когда я перемещаю шкалу.

Но - gtk_signal_connect вызывается только один раз. Хорошо, я понимаю, что это, вероятно, связано со стеком вызовов, этот бит памяти больше не резервируется.

Но я сделал то же самое ранее для другой панели, и она работает нормально. то, что я изменил, - это попытаться сделать вещи немного более аккуратными.

В предыдущей версии у меня были все панели и виджеты каждая в отдельных массивах. например,

GtkWidget **outerPanel;
GtkWidget **innerPanel1; 
GtkWidget **vscale1; 

тогда как этот я делаю:

typedef struct 
{
    GtkWidget **vscale1;
    Gtkwidget **vscale2; 
} V_Panel;

V_Panel **vscale_struct; 

Не надо класть панели в массивы или структуры - потому что я полагаю, что мне не нужен доступ к ним позже? (Я обнаружил, что вы можете «перерабатывать» метки, поэтому я считаю, что панели (h и vbox) одинаковы.

Также - интересная подсказка - когда я запускаю valgrind - все работает отлично. Некоторые из того, как valgrind меняет способ, которым программа использует свою память.

Любая помощь здесь? Если вы можете объяснить, что происходит, когда вы вызываете gtk_signal_connect. -

Вот мой фактический код: http://pastebin.com/MGfUihjM

соответствующие строки 45, 145, 274, 308, 391

1 Ответ

2 голосов
/ 26 февраля 2012

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

. Правильный способ упаковки целого числа value_id в указатель пользовательских данных обратного вызова -используйте GINT_TO_POINTER и поверните его, используя GPOINTER_TO_INT.

Таким образом, ваше сигнальное соединение будет:

gtk_signal_connect(GTK_OBJECT(vscale_struct[button_id]),
                   "value_changed",
                   (GtkSignalFunc)vscale1Event,
                   GINT_TO_POINTER(value_id)); 

А в вашем обработчике сигнала будет выглядеть так:

...