2014-10-01 112 views
1

問題是:在函數之間共享數據的最佳方式是什麼,但特別是在GTK/C應用程序中?最好的意思是最「合適的」,最快的運行和/或吸收儘可能低的CPU功率。
我在問,因爲我不得不在linux下用GUI編寫一些應用程序,但我只是一個單片機程序員(也許我很難像大電腦那樣思考)。在小型8位MCU的世界中,代碼以普通的C語言編寫,全局變量是在函數間共享數據的最快和常用的方式。
但我想,在操作系統下運行的更復雜的應用程序中,必須有其他「特殊」方式來執行此操作。到目前爲止,我注意到GTK(GDK,Glib等)提供了許多特殊的函數和內建機制來使程序員的生活變得最簡單,所以我認爲它應該是優雅的用於在函數之間共享變量。 通過網絡搜索我見過不同的解決方案:
- 具有私有變量和方法來獲得/設置它們的類 - 但我的應用程序使用C編碼,而不是C++,我想避免使用對象編程,
- 全球結構甚至是一個擁有衆多成員的大型全球結構,
- 好普通全局變量,
- GtkClipboard,但我認爲它是爲了不同的目的。GTK/C在函數之間共享數據和變量

我想要做的僅僅是在一個回調函數中設置一個變量'A',在第二個回調中再次設置該變量,然後在另一個回調中根據變量'A'的值做一些事情,像這樣:

callback_func1{ 
//... 
A = some_func(); 
//... 
} 
callback_func2{ 
//... 
A = another_func(); 
//... 
} 
callback_func3{ 
//... 
if(A>threshold) do_something(); 
else do_nothing(); 
//... 
} 

回答

2

對於全局變量的警惕,尤其是如果你只想讓某些函數修改它們的話。

假設你不僅僅是A(爲簡單起見,我定義爲int),你可以設置你的結構,包括其他數據成員在必要時熟悉的方式

typedef struct t_MYCBSD 
{ 
    int A; 
    // other members 
} MYCBSD; // callback struct data 

保留更多的數據。 (如果有一些自引用,我已經包含了t_MYCBSD)。

然後你可以實現你的回調函數如下:

void callback_func1(GtkWidget *widget, gpointer user_data) 
{ 
    MYCBSD *data = user_data; 
    data->A = some_func(); 
} 

void callback_func2(GtkWidget *widget, gpointer user_data) 
{ 
    MYCBSD *data = user_data; 
    data->A = another_func(); 
} 

void callback_func3(GtkWidget *widget, gpointer user_data) 
{ 
    MYCBSD *data = user_data; 

    if(data->A > threshold) do_something(); 
    else do_nothing(); 
} 

顯然,some_func()another_func()thresholddo_something()do_nothing()是在這方面有效。

注意:data指向您的結構的指針使語法更清晰一點。您還可以使用:

((MYCBSD *) user_data)->A = some_func(); 

無論如何,您通常在創建小部件時設置回調。在以下(嚴重剔除,非GtkBuilder)代碼中,MYCBSD mydata將在本地範圍內。我假設回調將設置爲「點擊」事件的一些按鈕。

int main(int argc, char* argv[]) 
{ 
    MYCBSD mydata; 
    // Below-referenced widgets 
    GtkWidget *mywidget1, *mywidget2, *mywidget3; 
    // ... other widgets and variables 

    mydata.A = 0; // Optionally set an initial value to A 

    // Standard init via gtk_init(&argc, &argv); 

    // ... Create the toplevel and a container of some kind 

    // Create mywidget1,2,3 (as buttons, for example) 
    mywidget1 = gtk_button_new_with_label ("widget1"); 
    mywidget2 = gtk_button_new_with_label ("widget2"); 
    mywidget1 = gtk_button_new_with_label ("widget3"); 

    g_signal_connect(mywidget1, "clicked", G_CALLBACK(callback_func1), &mydata); 
    g_signal_connect(mywidget2, "clicked", G_CALLBACK(callback_func2), &mydata); 
    g_signal_connect(mywidget3, "clicked", G_CALLBACK(callback_func3), &mydata); 

    // ... Attach those widgets to container 
    // ... and show all 

    // Run the app in a standard way via gtk_main(); 

    return 0; 
} 

最重要的這裏行是:

g_signal_connect(mywidget1, "clicked", G_CALLBACK(callback_func1), &mydata); 
    g_signal_connect(mywidget2, "clicked", G_CALLBACK(callback_func2), &mydata); 
    g_signal_connect(mywidget3, "clicked", G_CALLBACK(callback_func3), &mydata); 

其中最後一個參數傳遞數據的回調函數。

如果你只是想分享一個值,A,你可以以類似的方式傳遞它,而不需要結構。

+0

嘿,我一直在使用這些結構來在回調之間共享Gtk Widgets,我不認爲它也是共享標誌和變量的最簡單方法。現在很清楚! – 2014-10-15 18:29:12

0

如果你想使用全局變量,只需使用全局變量。而且,不管世界怎麼說,沒有人會因爲使用全局而死亡。

Globals被避免,因爲使維護困難程序,並從您的描述,這似乎並不是這種情況。

在共享方面,GTK +程序通常不是平行的,所以你可以自由地訪問RW中的全局變量而沒有任何問題。而且在使用任務時,最好將所有GTK +調用放在同一個任務上:您仍然可以從同一個任務中訪問RW中的全局變量。

+0

我的程序長大了,正如你所說,慢慢地變得「難以維護」。將全局包裝到結構中也是一個「良好的編程實踐」的問題,即使在小而簡單的應用程序中,你不覺得嗎? – 2014-10-15 18:24:16

+0

將數據打包到結構中並在全局空間中實例化*表示*使用全局變量。您特意要求在GTK +中共享數據的最快方式,答案是使用全局變量。它帶來了一些缺點,但它們大多是組織性的,而不是技術性的。 – ntd 2014-11-02 08:48:34

+0

有意思,你的意思是什麼缺點? – 2014-11-08 13:22:54