12

RTOSを備えたRAM制限付き組み込みマイクロコントローラー用にCでプログラミングしています。

私は定期的にコードを短い関数に分割していますが、すべての関数呼び出しにはより多くのスタック メモリが必要です。すべてのタスクは自分のスタックを必要とし、これはプロジェクトの重要なメモリ消費者の 1 つです。

コードを適切に整理して読みやすくし、メモリを保持する代替手段はありますか?

4

10 に答える 10

11

呼び出しスタックをフラットにするようにしてください。そのため、どの呼び出しを呼び出すa()のではなく、呼び出し、、およびそれ自体を呼び出します。b()c()d()a()b()c()d()

関数が 1 回だけ参照される場合は、それをマークinlineします (コンパイラがこれをサポートしていると仮定します)。

于 2008-09-25T19:05:28.920 に答える
10

スタックの使用には 3 つのコンポーネントがあります。

  • 関数呼び出しの戻りアドレス
  • 関数呼び出しパラメーター
  • 自動(ローカル)変数

スタックの使用を最小限に抑えるための鍵は、パラメーターの受け渡しと自動変数を最小限に抑えることです。実際の関数呼び出し自体のスペース消費はかなり最小限です。

パラメーター

パラメーターの問題に対処する 1 つの方法は、多数のパラメーターではなく、(ポインターを介して) 構造体を渡すことです。


foo(int a, int b, int c, int d)
{
...
   bar(int a, int b);
}

代わりにこれを行います:


struct my_params {
   int a;
   int b;
   int c;
   int d;
};
foo(struct my_params* p)
{
   ...
   bar(p);
};

この戦略は、多くのパラメーターを渡す場合に適しています。パラメータがすべて異なる場合、うまく機能しない可能性があります。多くの異なるパラメーターを含む大きな構造体が渡されることになります。

自動変数 (ローカル)

これは、スタックスペースの最大の消費者になる傾向があります。

  • 配列はキラーです。ローカル関数で配列を定義しないでください!
  • ローカル変数の数を最小限に抑えます。
  • 必要最小限のタイプを使用してください。
  • 再入可能性が問題にならない場合は、モジュールの静的変数を使用できます。

すべてのローカル変数をローカル スコープからモジュール スコープに単純に移動する場合は、スペースを節約していないことに注意してください。スタック スペースをデータ セグメント スペースと交換しました。

一部の RTOS は、スレッドごとに「グローバル」ストレージを割り当てるスレッド ローカル ストレージをサポートします。これにより、タスクごとに複数の独立したグローバル変数を使用できるようになる可能性がありますが、コードが単純ではなくなります。

于 2008-09-27T14:14:04.787 に答える
6

In the event you can spare a lot of main memory but have only a small shred of stack, I suggest evaluating static allocations.

In C, all variables declared inside a function are "automatically managed" which means they're allocated on the stack.

Qualifying the declarations as "static" stores them in main memory instead of on the stack. They basically behave like global variables but still allow you to avoid the bad habits that come with overusing globals. You can make a good case for declaring large, long-lived buffers/variables as static to reduce pressure on the stack.

Beware that this doesn't work well/at all if your application is multithreaded or if you use recursion.

于 2008-09-25T19:10:30.780 に答える
5

最適化、特にアグレッシブなインライン化をオンにします。コンパイラは、呼び出しを最小限に抑えるためにメソッドをインライン化できる必要があります。使用するコンパイラと最適化スイッチによっては、一部のメソッドを としてマークするとinline役立つ場合があります (または無視される場合があります)。

GCC では、「-finline-functions」(または -O3) フラグと、場合によっては「-finline-limit=n」フラグを追加してみてください。

于 2008-09-25T19:04:08.533 に答える
1

組み込みセットアップでコードのスタック要件を評価するためにどこかで読んだトリックの 1 つは、開始時にスタック スペースを既知のパターン (16 進数の DEAD が私のお気に入り) で埋め、システムをしばらく実行させることです。

通常の実行後、スタック スペースを読み取り、操作中に置き換えられなかったスタック スペースの量を確認します。少なくとも 150% を残すように設計して、実行されていない可能性のあるすべてのあいまいなコード パスに対処します。

于 2008-10-14T11:59:07.173 に答える
0

ローカル変数の一部をグローバルに置き換えることはできますか?特にアレイはスタックを使い果たす可能性があります。

状況によって、関数間でグローバルを共有できる場合は、メモリフットプリントを減らすことができる可能性があります。

トレードオフのコストは、複雑さが増し、機能間の望ましくない副作用のリスクが高くなることと、メモリフットプリントが小さくなる可能性があることです。

関数にはどのような変数がありますか?私たちが話しているサイズと制限は何ですか?

于 2008-09-25T20:05:57.337 に答える
0

ここには存在しない問題を想像していると思います。ほとんどのコンパイラは、スタックに自動変数を「割り当てる」とき、実際には何もしません。

スタックは、「main()」が実行される前に割り当てられます。関数 a() から関数 b() を呼び出すと、a が最後に使用した変数の直後の記憶領域のアドレスが b() に渡されます。これは、b() が関数 c() を呼び出し、c のスタックが b() によって定義された最後の自動変数の後に開始される場合、b() のスタックの開始になります。

スタック メモリは既に存在し、割り当てられていることに注意してください。初期化は行われず、関連する処理はスタック ポインタを渡すことだけです。

これが問題になるのは、3 つの関数すべてが大量のストレージを使用し、スタックが 3 つの関数すべてのメモリに対応しなければならない場合だけです。大量のストレージを割り当てる関数をコール スタックの一番下に保持するようにしてください。つまり、それらの関数から別の関数を呼び出さないでください。

メモリ制約のあるシステムのもう 1 つのトリックは、関数のメモリを占有する部分を個別の自己完結型関数に分割することです。

于 2009-09-14T01:55:58.813 に答える
0

コンパイラと、最適化オプションの積極性に応じて、関数呼び出しごとにスタックが使用されます。したがって、おそらく関数呼び出しの深さを制限する必要があります。一部のコンパイラは、単純な関数に分岐ではなくジャンプを使用して、スタックの使用量を削減します。明らかに、関数を直接呼び出すのではなく、たとえばアセンブラ マクロを使用して関数にジャンプすることで、同じことができます。

他の回答で述べたように、インライン化は利用可能なオプションの 1 つですが、コード サイズが大きくなります。

スタックを消費するもう 1 つの領域は、ローカル パラメーターです。この領域は、ある程度制御できます。(ファイル レベルの) 静的を使用すると、静的 RAM 割り当てを犠牲にしてスタック割り当てを回避できます。グローバルも同様です。

(本当に) 極端なケースでは、スタック上のローカル変数の代わりに一定数のグローバル変数を一時ストレージとして使用する関数の規則を考え出すことができます。注意が必要なのは、同じグローバルを使用する関数が同時に呼び出されないようにすることです。(したがって、コンベンション)

于 2008-09-27T07:50:45.223 に答える
0

スタック スペースの保持を開始する必要がある場合は、より優れたコンパイラまたはより多くのメモリを取得する必要があります。

通常、ソフトウェアは成長します (新機能など) 。そのため、スタック スペースを維持する方法を考えてプロジェクトを開始する必要がある場合、最初から失敗する運命にあります。

于 2009-05-18T19:54:04.923 に答える