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

定数が何故スタック領域に配置されるのか

HEWとRX621で、コンパイルしています。

ローカル変数を「const」にすると、スタック領域に配置されます。

関数の最初で、定数をスタック領域にコピーするプログラムが書かれています。

「const static」にすれば、定数のセクションに配置されます。

「const」は定数で書き込めないんだから、スタック領域に書き込むのはおかしいと思うのですが。

  • In reply to Kon Nozomu(すと):

    > const char a[] = "A"; の書き方では、aはconst変数です(初期化が必要)。

    aは配列名であり変数ではありません。要素数を省略しなければ初期化も必須ではありません。

    > const char* const a = "A"; はconst変数で初期化が必要ですね(=最初の書き方)

    この場合も初期化は必須ではありません。const なので値の変更ができないだけです。

  • In reply to fujita nozomu:

    > コンパイラにとっては、ローカル変数の場合、

    > const int a = 1;

    > と

    > static const int a = 1;

    > は上記の前者の意味ならまったく同じですよね(ガンガン最適化されるでしょう)。

    auto 変数は個別のアドレスを持つので違います。

  • In reply to fujita nozomu:

    例えば以下のプログラムで hoge(0) と piyo(0) の結果は異なります。

    #include <stdio.h>
    
    const int* hoge(int b)
    {
        const int a = 1;
        if (b == 1 || &a == hoge(1)) {
            return &a;
        } else {
            return NULL;
        }
    }
    
    const int* piyo(int b)
    {
        static const int a = 1;
        if (b == 1 || &a == piyo(1)) {
            return &a;
        } else {
            return NULL;
        }
    }
    
    int main(void)
    {
        printf("hoge(0) = %p\n", hoge(0));
        printf("piyo(0) = %p\n", piyo(0));
        return 0;
    }
    
  • In reply to fujita nozomu:

    付き合っていただいて、ありがとうございます

    >> const char a[] = "A"; の書き方では、aはconst変数です(初期化が必要)。
    >
    > aは配列名であり変数ではありません。要素数を省略しなければ初期化も必須ではありません。
    >
    >> const char* const a = "A"; はconst変数で初期化が必要ですね(=最初の書き方)
    >
    > この場合も初期化は必須ではありません。const なので値の変更ができないだけです。

    私の勉強不足で、配列名とconst変数の違いがわかりませんが、
    CC-RX最新バージョンで、

    const char a[2];

    はエラーE0520257です。

    const char* const a;

    はエラーE0520257です。

    >> コンパイラにとっては、ローカル変数の場合、
    >> const int a = 1;
    >> と
    >> static const int a = 1;
    >> は上記の前者の意味ならまったく同じですよね(ガンガン最適化されるでしょう)。
    >
    > auto 変数は個別のアドレスを持つので違います。

    なるほど、これはよい覚え方ですね。勉強になりました。
    hoge()の内容は、テンポラリのアドレス返すので、使えないですが、反例としては理解しました。
    アドレスで外のスコープへ渡せることを考えずに、同じだと表現していました。
    piyo()の内容は、同じデータが2回配置されないように、文字列なんかでは私も使います。
    (環境によっては、定数の重複はビルド時にひとつにしてくれる機能があったりしますが、変更時に1個所さわるだけにしたいので)

  • In reply to pcook:

    > CC-RX最新バージョンで、
    >
    > const char a[2];
    >
    > はエラーE0520257です。
    >
    > const char* const a;
    >
    > はエラーE0520257です。

    CC-RX V2.04.01 にて下記のコードをコンパイルしたところ

    void hogera(const char* a)
    {
        (void)a;
    }
    
    void hoge(void)
    {
        const char a[2];
        hogera(a);
    }
    
    void piyo(void)
    {
        const char* const a;
        hogera(a);
    }
    
    void main(void)
    {
        hoge();
        piyo();
    }
    

    警告は出ますがビルドは成功しました。ひょっとして C++ でコンパイルされてるとかではないですか? C と C++ では const の機能は全く異なります。

    ========== 全ビルドの開始(2016年4月18日 13:27:48) ==========
    ------ ビルド開始(test, DefaultBuild) ------
    >test.c
    W0511179:The evaluation version is valid for the remaining 13 days.
    test.c(14):W0520257:Const variable "a" requires an initializer
    >DefaultBuild\test.abs DefaultBuild\test.mot
    The evaluation period has expired.
    Renesas Optimizing Linker Completed
    ------ ビルド終了(エラー:0個, 警告:2個)(test, DefaultBuild) ------
    ========== 終了しました(成功:1プロジェクト, 失敗:0プロジェクト)(2016年4月18日 13:27:53) ==========
    
  • In reply to fujita nozomu:

    最初の方の話に戻してしまいますが、昔からローカル変数(auto属性)で文字配列を宣言して初期化すると、スタックに確保されコピーが発生するので、static宣言するというテクニックがあったと思います。

    それにconstが付くと、その後の変更でコンパイルエラーが出るというだけの話ではないでしょうか。

    頭が良くて気の利いたコンパイラなら、最適化時に思いもよらない事はやってくれますが...

  • In reply to Kon Nozomu(すと):

    const int a=2;

    b +=a;

    よりも b +=2;の方が速いと思うしわかりやすいですね、たぶん adda.l er0,#2 とかにコンパイルされるんですよね、もっと早くしようとしたら

    register int a=2; これなんかどれぐらい早いんでしょうか?

  • In reply to IKUZO:

    fujitaさん

    はい、C++です。通りで噛み合わないわけで。。今回のは途中で気づけた内容でした。。
    不定で変数を使うとか、恐れ多いことはしないので、Cのconst仕様忘れてました。

    IKUZOさん

    そこまで期待して書いてますね。メモリ確保されるなんて思ってません (^^;
    最適化だけで言えば、ローカル変数で再代入されていなければ、
    const付いていなくても、コンパイラはconst扱いで定数伝播させるでしょうし。

  • In reply to pcook:

    プログラムにおいて定数は分かり易さのためだと思います。

    char Buffer[10];

    main()

    {

      int i;

      for(i=0;i<10;i++){

         Buffer[i]=' ';

      }

    }

    よりも

    #define BufferSize 10

    char Buffer[BufferSize];

    main()

    {

      int i;

      for(i=0;i<BufferSize;i++){

         Buffer[i]=' ';

      }

    }

    の方が、BufferSizeに意味を持たせることができて、検証も修正も安全に行えます。定数の概念はこれになると思います。また、この場合には、

    const int BufferSize = 10;

    にする価値は無いと思います。もともと、定数の定義はコードの分かりやすさのためにあると思います。

    他の言語とは異なりC言語ではポインタを使用するプログラマが多い事やファンクションのみにしたことでconstが必要になってしまったのだと思います。constの目的は定数の定義ではないと思います。

  • In reply to kijo:

    そうですよね、BufferSize等は#defineの方が一般的ですよね、constしたい場面等はconst char *st[]={"JP","US"};等の時ですね、ただPCの場合や多くの場合ROM、RAMにこだわっても意味がないですね、実行コード領域がRAMですから、P領域は保護がかけてあるだけです

  • In reply to IKUZO:

    皆さんC言語だったんですね。C言語なら#defineでいいんでないでしょうか。(他に無いので)
    無理やり理由を挙げれば、#defineはスコープが限定できないですね。名前汚染でぶつかったりしません?

    最初の方に「オブジェクト」とあったので反射的にC++で書いてしまっていました。そのあたりは加味して頂けると助かります (^^;
    C++はconstは言語的に定数でいいと思ってます。CC-RXを使う場合は、クラス内定数が使えないので、整数なら enumハック 使ってます。スコープはとにかく限定したいので。

    >IKUZOさん
    今回の話で文字列にも#define使えば、 コピーのオーバーヘッドなくなる可能性があると思いました。
    C言語なら使っていこうと思ってます。

  • In reply to pcook:

    pcook さん#defineは特に規定とか一般的ということについては知らないんですが、原始的Cを使用してきた私にとって

    const int b=3;

    abs=b*2-5;

    cc=x+y+b;

    というような場面ではconstじゃなくて#define使用していますよ(私的)ということでして、

    #define使用するとスコープがということですが適当に逃げてます例えば#define  関数名_変数名_変数型 subb_xp_int とか

    それに#defineが2重定義なら警告も出せるようで、あまり心配していません、enumもおっしゃるように便利なので最近使ってます

  • In reply to IKUZO:

    const を使う所は、配列ではないでしょうか。

    私の実験しているのは、メッセージのような文字列です。

    数値だとしても、配列番号を指定して呼び出す変数じゃないでしょうか。

  • In reply to リカルド:

    私もconstの使いどころは変更不可の変数です。専ら関数配列などに使用します。

    immediateな固定値はdefineを用いることが多いですね。

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