HEWとRX621で、コンパイルしています。
ローカル変数を「const」にすると、スタック領域に配置されます。
関数の最初で、定数をスタック領域にコピーするプログラムが書かれています。
「const static」にすれば、定数のセクションに配置されます。
「const」は定数で書き込めないんだから、スタック領域に書き込むのはおかしいと思うのですが。
関数内のオブジェクトに static を指定しないと暗黙的に auto ということになるので自動記憶域期間を持ちます。そのブロック内でのみの寿命を持つのでオブジェクトがスタック上に配置されるのは正しいです。
RAMじゃなくてROMでいいじゃんってお話ですよね。
仰る通り、ROMでいいと思いますし、場合によっては、定数領域でもなく即値でいいと思います。
const有無とstatic有無でどこに配置されるか、
コンパイラ/リンカのマニュアルに書いてあり、
コード書く人がコントロールできますよってことだと、私は捉えております。
といって、何の役にたつのか私にはイマイチ分からなかったりします。
RAMとROMでアクセスウェイト時間が違ったりする場合に、高速化のために配置制御したくらいです。
逆に、コンパイラにガンガン最適化して欲しい場合は、どう書けばいいんでしょうか (^^;
私のこれまでの考えではconstは不揮発性ROMに持つものと考えていました、スタック領域ということもあるのですか、初耳です、そうなるとconstで定数扱いした場合に関数コールするたびに値が違いはしないのか?ということですが関数の最初で、定数をスタック領域にコピーしているなら確かにconstと宣言したのと同じ動作はしますね、constとは必ずしもROMに持つとは限らないということですね、なるほどです、動作が正しければいいわけで特別な規則はないわけですね、ただ毎回最初で、定数をスタック領域にコピーしているならCPU時間が無駄ということには気がつかないんでしょうかね、関数の外でグローバルで宣言するのもありますが、見通しが悪くなりますし、いっそのこと#pragmaでも使用して強制的に割り当てるとか、コンパイラの最適化を最高にしてみてはどうですか、プログラムのコードをデータとして扱えないような制約でもあるのですかね、変数宣言するのはやめにして規定値をコード中で指定するようなやりかたにしてみることは可能でしょうかね、毎回最初で、定数をスタック領域にコピーしているのなら、後で書き換えがきくということですかねそうなるとconstにはならないような、const宣言したにもかかわらずstaticになってる
不確かな経験と遠い昔に読んだK&Rのプログラミング言語Cの記憶です。constは型修飾子で、そこで宣言されるのは、定数ではなく値の変化しない変数と認識してます。K&Rのプログラミング言語CではPASCALのような定数定義は無く、defineで大文字で記述するように決めていたような記憶があります。
みなさん、書き込み有難う御座います。
私の言いたいことは、IKUZOさんの書かれている通りで、スタックにコピーするだけ無駄だなと言う事です。
コピー元を使えば、メモリーも時間も節約できます。定数と書いたけど、実際の試験では文字列の事です。
メッセージだと固定データで変更しないですから、「const」を上手に使おうと言う事で実験してみました。
誤解を招くような書き方ですいません。
局所変数のお話に関してですが、
-------
まず、言語的に、const変数は、非constで初期化する書き方ができますので、
const int a = 1;
と
const int cached_result = Func(x);
はちょっと意味が違うと思います。後者も定数なんですが、初期化は動的で、書き換え禁止のような意味でしかないです。
後者は、あえて確保されるならRAMになりますよね。
-----
次に最適化の話で、よく使いまわす定数は、余っているレジスタに突っ込んで、使いまわされるのではないでしょうか。これは、RAMにもROMにも置かれないですよね。(というか、私はレジスタはRAMと捉える傾向なので、ほとんどの計算はRAM同士になっていると解釈します)
ビットや1バイトの定数なんかになると、即値で命令に埋め込まれてしまうのではないでしょうか。
コピーのオーバーヘッドについても、ROMアクセスにオーバーヘッドがあると有利不利は微妙ですね。
スレ主さんはRXなので、話がずれてしまいますが、RL78はRAMノーウェイト、ROMが3クロックくらいでしたっけ。
例えば、sin(x)の計算を高速化するために、結果のテーブルを作ったとします。よく使う場合は、RAMにコピーした方が速いです。
すいません、ここまでいくと、もう局所変数の話でもないですね。
レスが入れ違いになってしまいました。主題からずれてすいません。
最適化して無駄なことしてたら、コンパイラがダメ、ってことでいいです (^^;
リカルドです。
変数が何処に配置されるか調べた結果を報告します。
① const static char[] = "A" : C-1セクション
② static const char[] = "B" : C-1セクション
③ const char[] = "C" : スタックエリア
④ char[] = "D" : スタックエリア
⑤ static char[] = "E" : R-1、D-1セクション(初期値付き変数)
予約語の前後を入れ替えた、①と②は同じ。
③と④は、同じ。関数の頭で、定数をスタックにコピーする命令が入る。
③が①と同じになると思ったが、④と同じになった。
⑤は main() 関数を実行する前に、DセクションからRセクションにコピーしなければならない。
③は、次のようになりました。SMOVFで、複数データをコピーしています
MOV.L #L14,R2
MOV.L R0,R1
MOV.L #0000000AH,R3
SMOVF
リカルドさん、おもしろい情報ありがとうございます。
私としては、
const char* a = "A";const char* const b = "B";
の書き方で、aは非const変数、bはconst変数と思っていますが、書いて頂いた内容は、全て前者のものでしょうか。そうすると全てRAMになるかと思ったのですが、そうでもないんですねぇ。
ポインタ(配列)の代わりに、intあたりで試すといいかなと思いました。あと、最適化すると後ろのコードによって変わるかってところですね。
自分でも試したいのですが、しばらく出先です。すいません。
間違いがあったので、追記削除しました。
const char a[] = "A";の宣言だと、aには代入できないですね。私の勘違いでした。すいません。(const char* const a = "A"; と同じ扱いですかね)
> const char a[] = "A";> の宣言だと、aには代入できないですね。
代入でなく初期値なので問題ありません。
4っつ前の書き込みは、分かり易いように編集してあります。
試験したときの文字列はもっと長いので、転送バイト数のカウンタ値に食い違いが出ます。
要点は、このようなコピー命令が入っている事の証明です。