一定の定義済みサイズ (バッファーなど) でランタイム データを格納するのに適した場所はどれですか?ヒープ (malloc)、スタック (char buf[BUFSIZE]
関数内など)、または bss セクション (char buf[BUFSIZE]
グローバル領域内)。
4 に答える
それは、バッファで何をしたいかによって異なります。
通常、グローバルは避けるべきです。それらに伴う問題に陥らないように十分に注意する必要があります。
バッファーが 1 つの関数でのみ必要であり、BUFSIZE が大きすぎない場合 (最大数 KB)、ローカルにすることができます。ただし、ネストされた呼び出しが加算されるため、合計スタック使用量に注意してください。静的ローカルは、呼び出し間で値を保持したい場合にのみ必要であり、効果的にローカル スコープを持つグローバルになります。しかし、マルチスレッドを使用したり、再帰を使用したりする場合は、頭痛の種になります。
バッファが複数の関数呼び出しで使用されている場合、または BUFSIZE が非常に大きい場合は、malloc()/free() を使用してください。関数が頻繁に呼び出される場合は、関数呼び出しごとに別のバッファーを割り当てて解放するのではなく、一度関数の外に割り当て、すべての関数呼び出しを実行してから解放することをお勧めします。しかし、これは、関数の内部構造を外部の呼び出し元と不必要に結びつけるため、時期尚早の最適化に近いものです。
全体像として、プログラムが成長すると、より構造化して責任を明確に定義する必要があります。メモリ処理の場合、そうしないと、最終的に追跡できなくなります。このバッファは、特定のタスクを持つ特定のモジュールの作業の詳細です。典型的なアプローチは、構造体を使用して OOP の方法でデータを整理し、そのようなオブジェクトを割り当てて解放する create および destroy 関数を使用することです。バッファは、この構造体の一部になる可能性があります。
struct s_foo
{
char buf[BUFSIZE];
...
};
struct s_foo *foo_create (...);
void foo_destroy (struct s_foo *foo);
void foo_action (struct s_foo *foo);
これにより、それぞれが独自のバッファーを持ち、互いに独立した、任意の量の foo を並行して持つことができます。さらに、バッファーの内容は呼び出し間で保持され、静的変数に悩まされることはありません。
この場合、バッファーが関数間で共有されていない場合、IMO の最適なオプションはローカルの静的変数です。
void func(...) {
static char buf[BUFSIZE];
}
これにより、割り当て/割り当て解除の繰り返しと名前空間の混乱の両方が回避されます。
編集
このソリューションはスレッドセーフではありませんが、グローバル変数もそうではありません。
ロード時に割り当てられ、プログラムの存続期間を通じて残る静的変数が必要です。オプション 3、いわゆる「bss」セクションです。
サイズが限られているため、明らかにヒープが不足しています。再入可能ではなく、再帰に大混乱をもたらすため、静的も使用しません。というわけで、スタックフレームに入れます。
void f(...) {
char buf[BUFSIZE];
}
ところで、絶対に必要でない限り、静的またはグローバルを避けることをお勧めします。