いつもお世話になっております。
以下のようなプログラムで、loop1()はwhileを抜けられず復帰しないのですが、 loop2()は、正しく復帰します。
loop1と、loop2の違いは、Delay()を呼ぶか、呼ばないかの違いしか有りません。
タイマー割り込みによりTimerは、0になります。 (Flagは0のままとします。)
多分?ループ最適化による影響ではないかと思うのですが、コンパイルオプションを替えても状況は変わりません。
どの様なオプションが影響するか お教え願えないでしょうか?
int Flag ;int Timer;
void Delay( void ) { asm("NOP"); }
void Interrupt_1ms( void ) { if ( Timer > 0 ) Timer--; }
int loop1( void ) { Flag = 0; Timer = 100; while(1) { if ( Flag ) break; if ( Timer == 0 ) { return( 1 ); } } return( 0 ); }
int loop2( void ) { Flag = 0; Timer = 100; while(1) { Delay(); // 重要 if ( Flag ) break; if ( Timer == 0 ) { return( 1 ); } } return( 0 ); }
にもち さん、こんにちは。NoMaYです。お久しぶりです。コンパイラは何をお使いですか? RZに関して質問されていることが多いようですので、GNUARMかIAR ARM C/C++コンパイラでしょうか?[追記]あと、割り込みルーチンで更新される変数Timerにvolatileが付いていませんが、今回の質問用に付けなかったものですか? それとも、普段から付けないでいたりしますか?
にもち さん、こんにちは。NoMaYです。私の追記が行き違ったかな、という予感がするので自己レスです。これは移植元のSH4用のソースに付いていなかったから、かな、、、という気がしてきました、、、> [追記]> あと、割り込みルーチンで更新される変数Timerにvolatileが付いていませんが、今回の質問用に付けなかったものですか? それとも、普段から付けないでいたりしますか?
> GCCでは変数のオプションとしては以下のものがありますね
大昔に廃止になってるので今使える状況は稀でしょう。
https://www.gnu.org/software/gcc/gcc-3.4/changes.html> GCC no longer accepts the options -fvolatile, -fvolatile-global and -fvolatile-static. It is unlikely that they worked correctly in any 3.x release.
> 多分?ループ最適化による影響ではないかと思うのですが、 Cコンパイラは「ひとつの関数の中では volatile 指定されていないオブジェクトの内容は勝手に変化しない」前提でコード生成するので loop1() の中の処理では Flag は 0、Timer は 100 に初期化して以降、その状態が続く(ループ処理が終わらない)コードが生成されると思います。https://godbolt.org/z/X3NRVB 対して loop2() では、ループ処理の中で呼んでる関数 Delay() の中でインラインアセンブラが使用されており、コンパイラはインラインアセンブラの処理内容を理解しないため、そのわからない処理の中で Flag や Timer の内容が書き換えられる可能性を考慮してループ中に Flag や Timer のアクセスの度に内容をメモリから読み出します。https://godbolt.org/z/6-VZlk loop2() が復帰する理由はそれでしょう。 Delay() の中のインラインアセンブラを無効化すれば Delay() の処理で Flag や Timer の内容が書き変わらないことをコンパイラは理解するのでループ処理は終わらなくなるかもしれません。https://godbolt.org/z/PIVpif 同様に、Delay() を外部関数化して処理の内容をコンパイラに悟られないようすれば Loop2() は復帰するコードになるかもしれません。https://godbolt.org/z/5y2Mwb > コンパイルオプションを替えても状況は変わりません。 大昔の gcc では volatile 指定されていないオブジェクトを volatile 指定されているよう扱うコンパイルオプションが存在しましたが既に廃止されています。最適化レベル0を指定(`-O0')すれば一見うまくいくようなコードは生成されるかもしれませんが https://godbolt.org/z/TMilv8 「ひとつの関数の中では volatile 指定されていないオブジェクトの内容は勝手に変化しない」前提は変わらないので期待したコードが生成されるかは何の保証もありません。割り込み処理で変化をさせるオブジェクトについては素直に volatile 指定をする以外方法はないでしょう。