2014-10-01 155 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