こんにちわ。ojojと申します。
ループ内で宣言したローカル変数をウォッチウィンドウからチェックすると値などが'?'と表示され困っております。ループ外で宣言した場合は表示されるので、そうすればよいのですが出来ればスコープを短くしたいです。
対処法をご存じの方いらっしゃいましたらご教授いただけないでしょうか。
環境マイコン:RX23t仕様ソフトウェア:CS+ ver8.06.00コンパイラ:CC-RX V3.03.00エミュレータ:RENESAS E1エミュレータ
状況(ソースを出せないのでイメージです。スミマセン。)
パターン1main{ while(1){ static uint16_t test=0; test = 1; }//test がウォッチウィンドウで表示できない}
パターン2main{ static uint16_t test=0; while(1){ test = 1; }//test がウォッチウィンドウで表示できる。}
以上です
ほや様 ご回答ありがとうございます。
アセンブラリスティング出力を確認したところ、変数のアドレスが定義されているような記述は確認できました。
00000004 __$test$4://変数名だけ変更しています。00000004 04000000 .lword 00000004H
また、volatileをつけて変数を宣言してもウォッチウィンドウに、変数の値やアドレスが'?'で表示される問題は改善されませんでした。
> 変数のアドレスが定義されているような記述は確認できました。そうなるとメモリ参照ではなくレジスタ参照に置き換えられているという可能性が残ります。
> volatileをつけて変数を宣言してもウォッチウィンドウに、変数の値やアドレスが'?'で表示される問題は改善されませんでした。
ええー。volatileが付いていたら何が何でもメモリから読み出してメモリに書き戻す処理は実装されるはずですけどね。
リスティングのコードがどうなっているか確認してみてください。
> __$test$4$4ですと?同じ変数名でいくつも持たせているのですか。それだとスコープを指定しても1個しか表示対象にならないと思います。同名の変数だとウォッチパネルでアドレスを参照させる書き方にするやり方ぐらいしか思いつきません。
>そうなるとメモリ参照ではなくレジスタ参照に置き換えられているという可能性が残ります。
レジスタ参照になっているというのはどこから判断つくのでしょうか。調べたのですがさっぱりで…
>volatileが付いていたら何が何でもメモリから読み出してメモリに書き戻す処理は実装されるはずですけどね。>リスティングのコードがどうなっているか確認してみてください。
確認しましたが、volatileの有無では、ほぼリスティングのコードは変わっていないようです。
>同じ変数名でいくつも持たせているのですか。
いえ、同じ変数名はつけていません。
すみません、アセンブラ言語に習熟おらず、現状ざっくりしか調査できてません。時間見つけてもう少し調べてみます。
スコープを指定してだめならアドレスで参照するしかないと思います。変数のアドレスが0x404なら *(uint16_t *)0x404 みたいな感じで。> レジスタ参照になっているというのはどこから判断つくのでしょうか。変数を更新する時にメモリから一旦読み出して更新した後で書き戻しているのか、最初に1回だけ読み出して更新をレジスタ上で行っている(初期値だけ参照してメモリを使っていない)のかをコードから読み取ってください。> 00000004 04000000 .lword 00000004Hこれは、セクションの先頭から0x04に変数が初期値4で配置されている状態です。初期値が4ではない値として宣言されていても演算結果が常に定数になるのであれば定数に置き換えられたと考えられます。
脇から、失礼します。
> volatileが付いていたら
volatile は、最適化の対象外にする指示ではなかったでしょうか?
CS+を使ってますが、どうもローカル変数は当てにならない印象(最適化は初期設定 .. 最適化あり)static宣言は、あまり使うものではないので、、(固定で領域確保される、、再帰呼出し時に問題有り)困ったら、アセンブラ表示するか、外部のグローバル変数にコピーする対応でやっています。あまり賢くない感じです。特にレジスタ割当だと、複数の変数が同じレジスタに割り当てられるのですが、スコープの判断できてないようだし、、(間違った値を表示)
参考までに。
[追記]
volatile ですが、確かに指摘のように最適化の対象外というより、値が変動するとかの意味で、正確には最適化の対象外とはちょっと違っていたようです。失礼しました。(結果的には同じでも)
> volatile は、最適化の対象外にする指示ではなかったでしょうか?volatileは最適化そのものを禁止するキーワードでなく、変数へのread/writeアクセスを「省略しない」ようにするためのものなので、最適化を無効にした設定でもvolatileがあるかないかでコードは違ってきます。> 特にレジスタ割当だと、複数の変数が同じレジスタに割り当てられるのですが、スコープの判断できてないようだし、、(間違った値を表示)レジスタが使い回される時には変数がoptimize out にされて見えなくなったりする現象も同じ理由だと考えます。コンパイラがどういう区切りでスコープをデバッグ情報に反映するかの、キメの細かさに依存すると思います。ソースを見ている人間から見たら何をやってるんだと感じるかもしれませんが、デバッガとしてはデバッグ情報の通りに動いてるだけなんでしょうね。> static宣言は、あまり使うものではないのでデバッガで見えるようにするために使うものではないですが、似たようなグローバル変数をいくつも増やしたくはないので個人的には好んで使っています。値が残っている事でかえってバグになってしまった経験もあるので、考えて使わないといけませんね。
Cコンパイラのマニュアル (R20UT3123JJ0111 Rev.1.11)を見ると、
> A.1.2 通常時と割り込み時に使用する変数を定義する
...
> volatile 修飾子をつけて変数宣言すると,その変数は最適化の対象になりません。
とありますね。read/writeアクセスの省略も最適化の一部です。
ただ、どちらにしてもスコープの問題は残るので、今回の問題への影響は少ないとは思います。
最適化時にvolatile記述のある変数を除けて処理するのは、volatileの本旨ではなく実現手段だと考えています。定数の畳み込みと最適化は別なので全く同じではありませんがひっくるめて最適化と見なしても実害はないと思います。
KatoNagano様 ご回答ありがとうございます。
自分もこれまでも似たような現象のたびにグローバル変数に変更しウォッチしていたのですが、いい加減しっかり理由を把握したいなぁと思いまして…レジスタ割り当てになっているか調査してみます。
staticを使用している変数は、グローバルで利用してもいいような変数群なのですが、スコープを縮めようと今回利用した形です。
ちょっと忙しくて検証のほう遅れそうです。
ojojさん、
私の場合、ちょっと見たい時は、デバッガ上でアセンブラ表示させ、どのレジスタを使っているかを見てレジスタを見ます。継続してウォッチするのに向かないですが、それでなんとかなる場合が多いです。(継続する場合はグローバル)
昔、レジスタ使いまわしで、別の変数の値が表示されて振り回された事があります。(CS+では無いですが)その場合、止める場所を間違えると変数は既に有効でないので、値を取得できません。
最適化については、最適化した場合とそうで無い場合で結果が違う事がある(大抵はバグ)ので、なるべく最終形に近い形でデバックしたいと思っています。