16

組み込みアプリケーションを作成していますが、RAM のほとんどすべてがグローバル バイト配列によって使用されています。ファームウェアが起動すると、RAM の BSS セクション全体がゼロで上書きされますが、これは私の場合はまったく不要です。

特定の配列をゼロで初期化する必要がないことをコンパイラに指示する方法はありますか? これは、ポインターとして宣言し、malloc() を使用することでも解決できることはわかっていますが、それを避けたい理由がいくつかあります。

4

7 に答える 7

11

問題は、標準 Cが静的オブジェクトのゼロ初期化を強制することです。コンパイラがそれをスキップすると、C 標準に準拠しなくなります。

組み込みシステムのコンパイラには、通常、「コンパクト スタートアップ」などの非標準オプションがあります。有効にすると、静的/グローバル オブジェクトの初期化は、プログラムのどこでもまったく発生しません。これを行う方法は、コンパイラ、またはこの場合は gcc ポートによって異なります。

使用しているシステムについて言及すると、誰かがその特定のコンパイラ ポートの解決策を提供できる可能性があります。

これは、明示的に初期化する静的/グローバル (静的ストレージ期間) 変数が初期化されなくなることを意味します。static int x=1;実行時に初期化する必要があります。つまり、代わりにstatic int x; x=1;. 静的初期化が無効になっているコンパイラと互換性を持たせるために、この方法で組み込み C プログラムを作成することはかなり一般的です。

于 2013-02-04T12:06:03.333 に答える
10

私のツールチェーンに含まれるリンカー スクリプトには、特別な「noinit」セクションがあることがわかりました。

__attribute__ ((section (".noinit")))

/** 現在の RAM の内容が保持されるように、コンパイラが起動時に指定されたグローバル変数を自動的にゼロにならないように強制します。ほとんどの条件下では、電源が切断されると揮発性メモリの動作により、この値はランダムになりますが、システム ウォッチドッグのリセット後に値を戻すなど、特定の状況で使用される場合があります。

そのため、その属性でマークされたすべてのグローバル変数は、起動時にゼロ初期化されません。

于 2013-02-04T15:33:53.960 に答える
2

すべての組み込みコンパイラは、noinit セグメントを許可する必要があります。IAR AVR コンパイラでは、初期化したくない変数は次のように簡単に宣言されます。

__no_init uint16_t foo;

これの最も有用な理由は、変数がウォッチドッグまたはブラウンアウト リセットを超えて値を維持できるようにすることです。これはもちろん、コンピューター ベースの C プログラムでは発生しないため、標準 C から省略されています。

コンパイラのマニュアルで「noinit」などを検索してください。

于 2015-08-17T11:18:25.303 に答える
2

C 標準では、グローバル データをゼロに初期化する必要があります。

組み込みシステムのメーカーによっては、このオプションをバイパスする方法を提供している可能性がありますが、「ゼロへの初期化」が行われなかった場合に単純に失敗する典型的なアプリケーションが多数存在することは確かです。

一部のコンパイラでは、「bss」セクション以外の特性を持つ可能性のある追加のセクションを使用することもできます。

もう1つの選択肢は、もちろん「独自の割り当てを行う」ことです。これは組み込みシステムであるため、アプリケーションとデータを RAM にロードする方法、特にそのために使用されるアドレスを制御できると思います。

したがって、ポインターを使用して、独自のメカニズムを使用して、大きな配列が必要な場合に予約されているメモリ領域にポインターを割り当てることができます。これにより、かなり複雑な - の使用が回避され、malloc多かれ少なかれ永続的なアドレスが得られるため、後でデータがどこにあるかを探すことを心配する必要がなくなります。もちろん、これは別のレベルの間接性を追加するため、パフォーマンスにわずかな影響を与えますが、ほとんどの場合、配列が関数の引数として使用されるとすぐに消えます。 .

于 2013-02-04T12:09:43.613 に答える
2

次のようないくつかの回避策があります。

  • バイナリから BSS セクションを削除するか、そのサイズを 0 または 1 に設定します。ローダーがすべてのセクションにメモリを明示的に割り当てる必要がある場合、これは機能しません。これは、ローダーが単純にデータを RAM にコピーする場合に機能します。
  • C コードのように配列を宣言externし、別のアセンブリ ファイルのアセンブリ コードまたはリンカー スクリプトでシンボルを (アドレスと共に) 定義します。繰り返しますが、メモリを明示的に割り当てる必要がある場合、これは機能しません。
  • ローダーまたはmain().
于 2013-02-04T12:09:51.640 に答える
1

バイナリ形式に実際にBSSセクションがバイナリに含まれていると確信していますか? 私が使用したバイナリ形式では、BSS は、カーネル/ローダーに割り当ててゼロにするメモリの量を伝える単純な整数です。

C で初期化されていないグローバル変数を取得する一般的な方法は絶対にありません。これは、コンパイラ/リンカー/ランタイム システムの機能であり、それに非常に固有のものです。

于 2013-02-04T11:45:47.197 に答える