Top Page [◀◀]  2   3   4   5   6   7   8   9   ... [▶▶Last Page

変数への初期値

いつもお世話になっております。

[環境]   e2studio     RZ/A1L (R7S721021)

[質問]

以下のプログラムがあるとき 変数v2への初期値を置くオブジェクトが出ません。 (初期値0以外の変数にはオブジェクトが作られます。)

これは、その変数に割り当てられたメモリーの初期値が0であることを考慮し その上へオブジェクトを置くために初期値をコピーする必要がないと解釈しているせいだと思います。

初期値0に対するオブジェクトを作り出すオプションはあるでしょうか?

[Cソース]

int   v1 = 0x12345678;

int  v2 = 0;

int  v3 = 1;

int  v4 = 0x87654321;

sum( int s )

{

  return( s+v1+v2+v3+v4);

}

 

[アセンブラソース 初期値部分]

0000 78563412         .word    305419896
  25                      .global    v2
  26                      .bss
  27                      .align    2
  30                  v2:      
  31 0000 00000000         .space    4  <<<<<< 初期値が作られない
  32                      .global    v3
  33                      .data
  34                      .align    2
  37                  v3:
  38 0004 01000000         .word    1
  39                      .global    v4
  40                      .align    2
  43                  v4:
  44 0008 21436587         .word    -2023406815
  45                      .text
  46                      .align    2
  47                      .global    sum

  • わわいです
    グローバル変数の初期化に関するオブジェクトはありません
    これは、初期化ルーチンで処理すべきものです。
    お使いのツールチェインのマニュアルを見てみてください

    ・初期値なしの変数セクション:全ゼロで初期化
    ・初期化ありの変数:初期値のセクションがあるので、その値をコピー

    という処理を、main関数の実行前に実行する必要があります
  • In reply to わわい:

    わわい様 早速ありがとうございます。

    ご指摘の趣旨は判るのですが、 この場合「初期化ありの変数」になると思いますが
    v1, V3, V4に対する初期値コピーのオブジェクトは生成されており、main関数の前に実行されています。
    しかし、V2に対する初期値0のオブジェクトが生成されず、また、V2の割り当て領域は初期値無しのbss領域となっています。

    従って、e2studio(GNU)のコンパイラに そういったオプションがあるのではないかと思い探したのですが見つけられませんでした。
  • In reply to にもち:

    >v1, V3, V4に対する初期値コピーのオブジェクトは生成されており、main関数の前に実行されています。
    >しかし、V2に対する初期値0のオブジェクトが生成されず、また、V2の割り当て領域は初期値無しのbss領域と>なっています。

     初期値無しの整数だとゼロクリアする仕様だから、V2は初期値無しの領域に割り当てられたんじゃないんですか。
  • In reply to にもち:

    わわいです
    最適化の結果、初期値が0の変数は初期化なしのセクションに割り当てられる、というコンパイラがあってもおかしくはないです
    で、初期値ありの変数のオブジェクト、というのは、一般的にROM領域に割り当てられますが、その変数のアドレスをそのままROM領域にしてしまうと、変数の内容が変えれなくなります
    実際には、main関数の実行前に、その初期値のオブジェクトを、変数領域(RAMエリア)にコピーするという操作が必要です
  • 通常 .bssセクションの内容はmain() を呼びだす前に 0 で初期化されるので初期値のない大域オブジェクトや初期値として 0 やNULL が指定されているそれは .bss セクションに配置されて問題はなく、GCC のデフォルトの挙動もそうなっていますが、`-fno-zero-initialized-in-bss' というコンパイルオプションで変更も可能です。
    gcc.gnu.org/.../Optimize-Options.html
  • In reply to リカルド:

    リカルド様
    「初期値無し領域は0クリアして動作する...」まさにそのとおりなのですが 
    仮に0クリアしないシステムでアプリを動作させた場合、変数初期値V2=0;に対する初期化オブジェクトが出ないために誤動作してしまいます。

    変数初期値V1=0x12345678;や、変数初期値V3=1;には 初期化オブジェクトが生成されています。
    ここで、変数初期値V2=0;は、「初期値無し領域の初期値は0クリアで始まる」と言う前提があるから 最適化されV2=0が出ていないのだとは思います。

    V2=0を初期値付き領域に割り当ててくれれば問題ないのですが、 仮定/前提の影響でオブジェクトが生成されません。
    そこで、この機能をoffにするコンパイラオプションは無いでしょうか? と言う質問でした。

    [fujita nozomu ]様のreplyで解決しました。

    ありがとうございました。
  • In reply to わわい:

    わわい様 ありがとうございました。
    初期値無しの変数(BSS領域)は、 起動時all 0で動きだすという暗黙の了解があるようですね。
    私が手がけているシステムは、bss領域はあくまでも不定であるという了解の下に動作するようにしています。
    従って、初期値0の変数は0でなければ困るのです。(初期値を持たない変数は不定で良い)
    変数が不定で動作することによる弊害(バグ)は十分に理解しています。...初期値を代入してから動作させています。

    そこで、コンパイルオプションとして初期値0を持つ変数にも初期値0を起動時に埋め込むオブジェクトを生成する オプションは無いでしょうかと質問しました。

    [fujita nozomu ]様のreplyで解決しました。

    ありがとうございました。
  • In reply to fujita nozomu:

    [fujita nozomu ]様 ありがとうございました。  解決できました。

    私の手がけているシステムでは、このプログラムを一旦FLASHにそのまま書き込み、実行時に内部RAMにコピーして動作させています。
    実行時に内部RAMを0クリアしないで動作させますので どうしても初期値0を持った変数への初期化オブジェクトが欲しかったのです。

    ご指摘のオプション`-fno-zero-initialized-in-bss' で初期値0オブジェクトが生成されるようになりました。

    ありがとうございました。
  • In reply to にもち:

    >「初期値無し領域は0クリアして動作する...」まさにそのとおりなのですが 
    > 仮に0クリアしないシステムでアプリを動作させた場合、変数初期値V2=0;に対する初期化オブジェクト
    >が出ないために誤動作してしまいます。

     C言語の仕様として、mainを実行する前にゼロクリアするんです。
     そのプログラムは自分で作ったり、組み込んだりしないと行けません。

     この仕様に従うと、リセットのつもりでmain関数の頭に飛んでも初期値を書いてくれない。
     main関数内の頭で初期値を書くようにアレンジする事も出来ます。
     スタックポインタの設定も同様で、どこで設定するかはユーザがアレンジ出来ます。


    RX ファミリ C/C++コンパイラ、
    アセンブラ、最適化リンケージエディタ
    コンパイラパッケージ V.1.01 ユーザーズマニュアル


    201ページからの抜粋を書きます。

    (5) セクションの初期化処理
    RAM 領域セクションの初期化用ルーチン(_INITSCT)を呼び出します。未初期化データセクションはゼロ初期化
    されます。初期化データセクションは、ROM 領域の初期値をRAM 領域へコピーします。_INITSCT は、標準ラ
    イブラリとして提供されます。
    初期化対象のセクションは、ユーザがセクション初期化用テーブル(DTBL,BTBL)へ記述する必要があります。
    _INITSCT 関数が使用するセクションの先頭アドレスおよび最終アドレスを、セクションアドレス演算子を用いて
    設定します。
    セクション初期化用テーブルのセクション名は、未初期化データ領域をC$BSEC、初期化データ領域をC$DSEC
    で宣言します。
  • In reply to リカルド:

    >初期値無しの変数(BSS領域)は、 起動時all 0で動きだすという暗黙の了解があるようですね。

    特に指定しない変数をゼロにするのは暗黙ではなくANSI規格に明確に記載されていたと記憶してます。(チョットインターネットで検索したのですが情報が見つからず再確認できませんでした。)

  • In reply to kijo:

    返信いただいた皆様、 経緯をお読み頂いた皆様 原因が判明しました。

    プログラムの起動時に初期値及び、領域クリアを行うreset_program.asmが改変されており 初期値、領域クリアが正しく行われないようになっていました。
    結果として初期値0の領域が初期化されず 悩んでいました。
    reset_program.asmは、e2studioでプロジェクトを生成したとき自動的に組み込まれるソースであるため問題はないと思っていたのですが、最近私のローカルな環境で修正されており経緯の結果となっていました。

    正常に動作していれば、初期値無変数領域は0クリアされ、初期値付き領域は初期値を設定されることを確認しました。

    いろいろと、調査、ご指摘を頂き 大変ありがとうございました。
  • In reply to kijo:

    C言語の言語仕様としての記載は「6.7.8 初期化」で書かれています。
    以下で参照できます。(JIS X 3010から持ってきていますが、元はISO/IEC 9899(C99)です)
    kikakurui.com/.../X3010-2003-01.html

    ---
    自動記憶域期間をもつオブジェクトを明示的に初期化しない場合,その値は不定とする。静的記憶域期
    間をもつオブジェクトを明示的に初期化しない場合,次の規定に従う。

    a)そのオブジェクトの型がポインタ型の場合,空ポインタに初期化する。
    b)そのオブジェクトの型が算術型の場合,(正又は符号無しの)0 に初期化する。
    c)そのオブジェクトが集成体の場合,各メンバに a)〜d)の規定を(再帰的に)適用し初期化する。
    d)そのオブジェクトが共用体の場合,最初の名前付きメンバに a)〜d)の規定を(再帰的に)適用し初期化する。
    ---
  • In reply to Hos:

    わわいです
    まあ、ブートローダとか、API的に使うようなブロック(ユーザプログラムから繰り返し呼ばれるような)とかはあえて、変数エリアは初期化せず、コードで明示的に値を入れて使う、という使い方もしますね

    いちいち全エリアのクリアする時間がもったいない、使うときに使う分だけクリアでいーぢゃん、というかんがえかたですね
  • In reply to にもち:

    C言語の多くの教科書にコンパイラそのものはファンクションの入出力程度の機能に抑えてほとんどをライブラリでカバーすると書かれてます。例えば、PASCALのWRITEはコンパイラで対応しますが、Cの場合はprintfを呼び出すことで実現してます。出力装置が変わってもコンパイラをそのままでprintfファンクションを書き換えるだけで対応が可能で、移植性の良さのメリットとされてます。C言語の場合はライブラリなどもコンパイラの一部と考えアプリケーション開発者はあらかじめ用意されているコードの書き換えを控えないとせっかくの移植性や検証性のメリットが失われます。

Top Page [◀◀]  2   3   4   5   6   7   8   9   ... [▶▶Last Page