5

[.c] ファイル内の複数の関数からアクセスする必要がある変数を実装する方法を考え出そうと、ぐるぐる回っています。

私は Stack Exchange やその他の Google 検索でスレッドを次々と調べてきましたが、一般的な [しかし確かに全会一致ではない] コンセンサスは、ファイル全体の静的変数は問題ないと思われますが、変数 (または少なくともポインタ) を渡す必要があります。古い関数にファイル全体の静的変数 (つまり、関数の外で宣言されている変数)にアクセスさせるだけではありません。一部の人々は、ファイル全体の静的は基本的にグローバルと同じくらい悪いと言っていますが、ファイル全体の静的でない場合、グローバルを回避する方法を示していません!

ただし、ある時点で、ファイル全体の静的変数へのポインターを関数から関数に渡したとしても、一部の関数は最初にそのファイル全体の静的変数にアクセスする必要があります。また、静的変数を必要とするすべての関数が 1 つの関数を通過するわけではないため、.c ファイル内の 1 つの関数だけがその静的変数にアクセスする唯一の関数になる方法もわかりません。

静的変数を保持し、その静的変数へのポインターを返すだけの関数を作成できるように思えます。その変数にアクセスする必要がある関数は、その関数を呼び出し、変数へのポインターを取得し、変数に対して必要な処理を行います。このようなこと:

struct PacketStruct* GetPacketStructPtr(void)
{
    static struct PacketStruct Packet;

    return &Packet;
}

私はここで何人かの人々が、そうです、それがシングルトン ファクトリの構築方法であり (それが何であれ)、それは完全に有効であると言うのを見てきましたが、他の人はそれが危険だと言います (しかし、なぜそれが危険なのかを実際に説明することなく)、他の人はそれが悪い習慣だと言いました (彼らはそれが非効率的だと言ったと思いますが、今日私は間違っているかもしれません)。

だから、私が確認しようとしているのはこれです:

  1. ファイル全体の変数は問題ありませんか?

  2. もしそうなら、すべての関数がそのファイル全体の静的変数にアクセスし、それへのポインターを渡さない[静的ファイル全体の変数]-さまざまな変数で関数を再利用できるようにするのと同じくらい間違っているように思われることを考えると- ファイル全体の static にアクセスする必要がある最初の関数を決定して、ポインタを他の関数に渡すことができますか? ファイル全体の静的変数にアクセスするだけのコードの見た目は本当に嫌いですが、関数がアクセスできる何かへのポインターを渡すのは少しばかげているようにも思えます。

  3. ファイル全体の静的変数が有効でない場合、これがマルチスレッドではなく、組み込みマイクロで実行して完了するだけのプログラムであることを考えると、関数全体の静的変数にポインターを渡す方法を使用できます/使用する必要があります変数へのアクセスが必要な他の関数に?

  4. 上記のいずれでもない場合、恐ろしいグローバル変数をどのように回避しますか? グローバルを使用しないというこの問題は、ここで無数に取り組まれているようですが、それを行う方法の具体的な例はありません. Web の他の場所は言うまでもなく、ここには非常に多くの矛盾したアドバイスが飛び交っています!

これはシングルスレッドであり、再入可能ではなく、すべてが比較的単純であることを強調します。

うまくいけば、これは私がやろうとしていることについてもう少し考えを与えます:

#include "work_order.h    
        // This is work_order.c

    // Nothing outside of this file needs to access the WorkOrder struct
        static struct WorkOrderStruct WorkOrder;     

        // Package up a work order - *data is a pointer to a complete serial package
        int16_t CableConnectOrder(uint8_t *Data)
        {

            if (UnpackagePortInformation(&WorkOrder.PortA,&Data) == CARD_UID_NOT_FOUND)
                return CARD_UID_NOT_FOUND;
            if (UnpackagePortInformation(&WorkOrder.PortB,&Data) == CARD_UID_NOT_FOUND)
                return CARD_UID_NOT_FOUND;

            AddNewKeysToWorkOrder(&WorkOrder,Data); 

            WorkOrder.WorkOrderType = CONNECT_CABLE_REQUEST;
            WorkOrder.Flags.SingleEndedConnection = FALSE_BIT;
            WorkOrder.Flags.PortACableRemoveRequest = FALSE;
            WorkOrder.Flags.PortBCableRemoveRequest = FALSE;

            return ConstructCableOrderRequest(&WorkOrder);

        }


        int16_t ConstructCableOrderRequest(struct WorkOrderStruct *WorkOrder)   
        {

        // This function is accessed by other Work Order requests and does the rest of the        // packaging of the work order
        // It can also pass the work order information further down
        DoOtherStuff(WorkOrder); // Kind of further passing that might happen


        }

        int16_t CheckAdditionalInfoAgainstWorkOrder(struct WorkOrderPortUpdateStruct *Update)
        {

            // Compare connection information against the previously set-up work order
            // Needs to access the static WorkOrder structure as well. Also, can call other
            // functions that needs to access the static function
        WorkOrder.Foo = Update->bar;
        DoYetMoreOtherStuff(&WorkOrder); // This is not real code, but the general kind of idea

        }
4

1 に答える 1

1

あなたが何をしているかについてのより多くの情報は役に立ちます。私はよく、組み込みシステムのプログラミングを行います。そこでは、割り込みのためにグローバル/ファイル全体の静的が絶対に必要です。それがあなたが取り組んでいることであるなら、それを実行してください。

Re:変数を作成し、他のすべての関数にポインターを渡す単一の関数...「単一の関数」がメインになります。私はしばしばそのようなコードを作成します...

struct PacketStruct {
    char name[128];
    uint8_t age;
    float bac;
}

void setup (PacketStruct *packetStruct, ...);
void foo (PacketStruct *parameter);
void bar (PacketStruct *parameter);

int main (void) {
    PacketStruct ps;

    // Initialize all variables"
    setup(&ps);

    // Run program
    foo(&ps);
    bar(&ps);

    return 0;
}

void setup (PacketStruct *packetStruct, ...) {
    strcpy(packetStruct->name, "Squidward");
    packetStruct->age = 16;
    packetStruct->bac = 0.11;
}

psはグローバル変数ではなく、メモリを動的に割り当てる必要がなく (同じように簡単に割り当てることができます)、すべての関数でアクセスできるため、私はこれが気に入っています。

繰り返しになりますが、完全なコード (またはその使用方法を示すスニペット) を投稿していただければ、アプリケーション固有のアドバイスを提供できる場合があります。

-編集-ファイル全体について言及しているので、メインと同じファイルでこの変数を使用していないことを意味していると思います。その場合、私のサブファイルには次のような機能がありますfilename_init(...)...

/* File:   FooBar.c
 */

#include "FileWithPacketStructAndOtherCoolThings.h"

// "g_" sits in front of all global variables
// "FooBar_" sits in front of all file-wide statics
static PacketStruct g_FooBar_ps;

FooBar_init(void) {
    strcpy(g_ps->name, "Squidward");
    g_ps->age = 16;
    g_ps->bac = 0.11;
}
于 2013-09-16T16:31:03.713 に答える