1

問題は、関数間でデータを共有する最良の方法は何ですか?特に GTK/C アプリケーションでは? 最良とは、最も「適切」で、実行が最も速く、および/または可能な限り低い CPU パワーを吸収することを意味します。
LinuxでGUIを使用してアプリをコーディングする必要があるため、質問していますが、私はむしろマイクロコントローラープログラマーです(おそらく、大きなコンピューターのように考えるのは難しいです)。コードが単純な C で記述されている小さな 8 ビット MCU の世界では、グローバルは関数間でデータを共有するための最速で一般的に使用される方法です。
しかし、オペレーティングシステムの下で実行されているはるかに複雑なアプリでは、それを行うための他の「特別な」方法が必要だと思います。この時点で、GTK (GDK、Glib など) が多くの特別な関数と組み込みメカニズムを提供してプログラマーの作業を楽にすることに気付きました。したがって、関数間で変数を共有するための洗練されたものであるべきだと思います。ネットを検索すると、さまざまな解決策が見つかりました:
-プライベート変数とそれらを取得/設定するメソッドを持つクラス-しかし、私のアプリはC++ではなくCでコーディングされています。オブジェクトプログラミングの使用を避けたい
-グローバル構造体または多くのメンバーを持つ 1 つの大きなグローバル構造体
- 良い単純なグローバル
- GtkClipboard ですが、それは別の目的のためだと思います。

私がやりたいことは、ある変数 'A' を 1 つのコールバック関数で設定し、その変数を 2 番目のコールバックでもう一度設定してから、別のコールバックで変数 'A' の値に応じて次のように何かを行うことです。

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

2 に答える 2

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たい場合は、構造体を必要とせずに同様の方法で渡すことができます。

于 2014-10-01T21:56:57.160 に答える
0

グローバルを使用する場合は、グローバルを使用してください。そして、世界が何と言おうと、グローバルを使用したために死亡した人は誰もいません。

大規模なプログラムではメンテナンスが困難になるため、グローバルは避けられます。あなたの説明からすると、そうではないようです。

共有側では、GTK+ プログラムは通常並列ではないため、RW のグローバルに問題なく自由にアクセスできます。また、タスクを使用する場合は、すべての GTK+ 呼び出しを同じタスクに配置することをお勧めします。同じタスクから RW のグローバルにアクセスすることは引き続き許可されます。

于 2014-10-05T08:03:27.233 に答える