1

大規模なプロジェクト内で、同じメモリ構造で動作する C 関数のリストを作成します。これらの関数はコードの非常に異なる部分 (および個別にコンパイルされてからリンクされる異なるライブラリ) で呼び出されるため、各関数呼び出しの引数としてメモリ構造へのポインターを渡す必要がないようにしたいと考えています。

メモリ構造を静的変数として単一の関数に格納し、他の関数内で常にその関数を呼び出して、メモリ構造へのポインタを取得することを考えていました。以下のサンプルでは、​​ポインターstorage()を設定するために使用しています。sto

以下のコードをテストしましたが、問題なく動作するようです。これは標準的なアプローチですか?私が実行しているリスクは何ですか? それは常に機能しますか?より良い解決策はありますか?

関数への同時呼び出しはありません。もちろん、割り当てられたメモリも解放する必要があります。

#include <stdio.h>
#include <stdlib.h>

int* storage(int get_set)
{
    static int* sto;
    if (get_set==1)
    {
        sto=malloc(2*sizeof(int));
        sto[0]=1;
        sto[1]=2;
    }
    printf("storage: content = %d %d, pointer= %d\n", sto[0], sto[1], sto);
    return sto;
}

void add11()
{
    int* sto =storage(0);
    sto[0]+=1;
    sto[1]+=1;
    printf("add11: content = %d %d, pointer= %d \n", sto[0], sto[1], sto);
}

void multo0()
{
    int* sto =storage(0);
    sto[0]=sto[1]*sto[0];
    sto[1]=0;
    printf("multo0: content = %d %d, pointer= %d\n", sto[0], sto[1], sto);
}


int main(void) {
    storage(1); // initialize memory only once
    add11();  // work on memory 
    multo0();
    add11();
    // ...
    return 0;
}

このようなものが欲しかった理由は次のとおりです。

私が書いている一連の関数は、画像強調の別の補助的なオプションのタスクを実行し、以前に観察された画像からさまざまな方法で学習します。 stoこの学習とパラメーター化オプションのメモリを保存します。

プロジェクト全体で、私の関数は複数のネストされた関数呼び出しで呼び出されます。引数として渡すstoということは、プロジェクトのメインで a ポインターを宣言し、関数によって実行されるタスクとは関係のない多数のネストされたコア関数を変更して、追加の引数を渡すことを意味します。

また、同じ関数セットを複数のわずかに異なるプロジェクトに統合する必要があるため、外部コードの変更を最小限に抑える必要がある、あまり邪魔にならない統合がプラスになります。

読みやすさの問題については、共有メモリにアクセスするすべての関数のみが同じプレフィックスを持っています。これが完全な解決策ではないことはわかっていますが、読みやすさが少し向上すると思います。

すべての機能をstoプロジェクト全体に適用するように変更する以外に選択肢はありませんか?

4

3 に答える 3

2

これにはいくつかの欠点があります

最初に、関数は呼び出されるたびにメモリを割り当てますが、呼び出し元が返されたものを明示的に解放する必要がある関数の名前からは明らかではありません。

次に、グローバル値として機能します。ポインターを使用して関数間でデータを渡すことをお勧めします。これは、読みやすさの観点から、関数プロトタイプを見るだけでどの関数がデータにアクセスするかがより明確になるためです。

void foo(storage* p);
void foo1();
void foo2(const storage* p);

3番目に、データにアクセスするときにオーバーヘッドを追加します

ストレージ関数にもメモリ リークがあり、sto を static として宣言しますが、malloc に割り当てる前に既に何かを指しているかどうかを確認しません。

static int* sto;
if (get_set==1)
{
    sto=malloc(2*sizeof(int));
    sto[0]=1;
    sto[1]=2;
}

次のようなものでなければなりません

static int* sto;
if (get_set==1)
{
    if ( sto != NULL ) 
    {
      free(sto);
    }
    sto=malloc(2*sizeof(int));
    sto[0]=1;
    sto[1]=2;
}

それでもこのメソッドを使用することを主張する場合は、少なくとも値を構造体に入れる必要があります。その後、値がコピーされ、毎回ヒープを割り当てる必要はありません (オーバーヘッドが増えるという欠点があります)。

typedef struct
{
  int a[2];
} storage_ret;

storage_ret storage(int get_set)
{
    static storage_ret sto;
    if (get_set==1)
    {
        sto.a[0]=1;
        sto.a[1]=2;
    }
    printf("storage: content = %d %d, pointer= %d\n", sto.a[0], stoa.[1], &sto);
    return sto;
}
于 2013-10-03T08:37:28.743 に答える
2

一緒にリンクしている複数のモジュールが既にあるため、「より標準的な」アプローチは、静的(単一モジュールのプライベート)変数(最初のアプローチ)を持ち、アクセサー関数が必要な場合はそれへのポインターを返すことです。ただし、アクセサーが単純にポインターを返す場合は、単に「extern」を使用して、自然な方法でデータにアクセスできます (2 番目のアプローチ)。

最初のアプローチ:

データを含むモジュール:

static int mydata; /* note: "static" */

int* accessor() {
    return &mydata;
}

データを使用するモジュール:

int* accessor();

int main() {
    int* foo = accessor();
}

2番目のアプローチ:

データを含むモジュール:

int mydata; /* note: no "static" */

データを使用するモジュール:

extern int mydata; /* note: "extern" */

int main() {
    int* foo = &mydata;
}

2 番目のアプローチは、「より C 風」で高速です。通常の方法は、2 番目のケースでは単に "mydata" を通常のローカル変数であるかのように使用し、ポインターのためだけにポインターを導入しないことに注意してください。ここでは、最初のケースと一致するようにしました。

于 2013-10-03T08:45:31.753 に答える
0

これは確かに標準的な方法ではなく、コードの可読性に関するレベルの懸念を追加します。あなたのプロジェクトに追加されたばかりで、このコードを使用する必要がある人を想像してみてください。彼/彼女は本当に混乱するでしょう。また、関数呼び出しごとにオーバーヘッドが発生する可能性があるため、すべての関数にポインターを渡すことをお勧めします。

于 2013-10-03T08:34:00.640 に答える