[.c] ファイル内の複数の関数からアクセスする必要がある変数を実装する方法を考え出そうと、ぐるぐる回っています。
私は Stack Exchange やその他の Google 検索でスレッドを次々と調べてきましたが、一般的な [しかし確かに全会一致ではない] コンセンサスは、ファイル全体の静的変数は問題ないと思われますが、変数 (または少なくともポインタ) を渡す必要があります。古い関数にファイル全体の静的変数 (つまり、関数の外で宣言されている変数)にアクセスさせるだけではありません。一部の人々は、ファイル全体の静的は基本的にグローバルと同じくらい悪いと言っていますが、ファイル全体の静的でない場合、グローバルを回避する方法を示していません!
ただし、ある時点で、ファイル全体の静的変数へのポインターを関数から関数に渡したとしても、一部の関数は最初にそのファイル全体の静的変数にアクセスする必要があります。また、静的変数を必要とするすべての関数が 1 つの関数を通過するわけではないため、.c ファイル内の 1 つの関数だけがその静的変数にアクセスする唯一の関数になる方法もわかりません。
静的変数を保持し、その静的変数へのポインターを返すだけの関数を作成できるように思えます。その変数にアクセスする必要がある関数は、その関数を呼び出し、変数へのポインターを取得し、変数に対して必要な処理を行います。このようなこと:
struct PacketStruct* GetPacketStructPtr(void)
{
static struct PacketStruct Packet;
return &Packet;
}
私はここで何人かの人々が、そうです、それがシングルトン ファクトリの構築方法であり (それが何であれ)、それは完全に有効であると言うのを見てきましたが、他の人はそれが危険だと言います (しかし、なぜそれが危険なのかを実際に説明することなく)、他の人はそれが悪い習慣だと言いました (彼らはそれが非効率的だと言ったと思いますが、今日私は間違っているかもしれません)。
だから、私が確認しようとしているのはこれです:
ファイル全体の変数は問題ありませんか?
もしそうなら、すべての関数がそのファイル全体の静的変数にアクセスし、それへのポインターを渡さない[静的ファイル全体の変数]-さまざまな変数で関数を再利用できるようにするのと同じくらい間違っているように思われることを考えると- ファイル全体の static にアクセスする必要がある最初の関数を決定して、ポインタを他の関数に渡すことができますか? ファイル全体の静的変数にアクセスするだけのコードの見た目は本当に嫌いですが、関数がアクセスできる何かへのポインターを渡すのは少しばかげているようにも思えます。
ファイル全体の静的変数が有効でない場合、これがマルチスレッドではなく、組み込みマイクロで実行して完了するだけのプログラムであることを考えると、関数全体の静的変数にポインターを渡す方法を使用できます/使用する必要があります変数へのアクセスが必要な他の関数に?
上記のいずれでもない場合、恐ろしいグローバル変数をどのように回避しますか? グローバルを使用しないというこの問題は、ここで無数に取り組まれているようですが、それを行う方法の具体的な例はありません. 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
}