ようこそ!JQ2RVNのブログです。
PICを使っていろいろな物を作ろうと画策中です。
× [PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
C言語の関数で2つ以上の返値を出したいときや、
もともとの変数を直接いじりたいときには、 ポインタを使うのが定石だと思います。 通常のC言語での使い方は・・・・ void func( int* a ) { *a=....; (この後の例では、*a++;を使います) } 呼び出しは func( &x ); となります。 しかし、CCSCの場合は、これではうまく動かないようです。 アセンブラリストを見ると次のようになっています。 まずは呼び出し方。 MOVLW 32 (32は変数xのアドレス) MOVWF 33 (33はfunc関数の引数aのアドレス) GOTO 060 (func関数の番地) (32や33、060という値は、コンパイラが自動的に変更してくれます。) 「33番地に、変数Xのアドレス(32)を入れて、func関数に飛ぶ」 となるので、参照動作(&がついた時の動作)は問題ないようです。 次に、func関数 060 MOVF 33,W 061 INCF 33,F 062 GOTO xxxx これを見ると変なことがわかります。 061は関数内の処理、a++;に相当するのですが、 それがINCF 33,Fとなって、33番地の内容を直接インクリメントしています。 はじめは32が入っていたので、1プラスされて33になるだけなので、 予期していた動作と違うことがわかると思います。 結論として、ポインタ呼び出しはCCSは使えないことになります。 さて、これでは使いにくいので、次のような方法があります。 void func( int8 &a ) { a++; } 呼び出し側は、 func( a ); この場合のアセンブラリストは・・・ 呼び出し側:何も記載がない(呼び出す直前のプログラムメモリは0C3) 関数側: 0C4 INCF 32,F つまり、コンパイラは関数のコールやジャンプなしに、 直接0C4番地にインクリメント命令を出しています。 なるほどといえば、なるほどな処理ですね。 もし、2か所以上から関数の呼び出しをしている場合はどうなるか? 064 INCF 36,F 0C4 INCF 32,F というように、同じ処理が2つ書かれます。 なんてことはない、インライン展開をしてるわけですね。 インライン展開にはソースの可読性もよくなり、 ポインタを意識せずとも、関数を使うことができます。 しかし、必然的にプログラムメモリの使用量は増えるので、 複雑な処理を、何か所からかコールするという場合には不適です。 その場合は、グローバル変数を用意しておいて、 そこに値を書き込んでいく処理が必要になります。 なお、MPLAB Cの場合はポインタ変数が使えますから、 最初の例のままでOKです。 PR CCS Cコンパイラを使っている時、 まず、以下のような処理を考えます。 UARTで8ビットのデータを送信するとき、 通常ならば、while文を使うところですが、 順当に書けばこんな感じでしょうか? i++; if( i > 8 ) しかし、この場合if( i > 8 )の計算のために
逆にiを減算していったほうが、処理としてはスマートになります。 i--; if( i == 0 ) こうしておくと、 どうやら、i==0と比較しようとすると、
このあたりを考慮すると、if文内はビット演算として書かないといけないようです。 さらに、デクリメント演算はif文の中に入れてしまう。 まとめると、 if( ! --i ) と書きます。 コンパイルされたアセンブラは以下のようになります。 decfsz i,f 処理B else 処理B end_if decfszは、
論理を逆にして
ポイントをまとめると
この原則を守ると、可読性が失われる時もありますが、
|
カレンダー
プロフィール
コールサイン:
JQ2RVN
性別:
男性
自己紹介:
PICの開発を勉強中です。
目標はPICTNCの高性能版を作ること。 まずは、本家を解析しています。
カテゴリー
最新記事
最新コメント
[04/23 Eolande]
[04/16 太田和巳(JF2UJG)]
[09/10 je7ifp]
[08/06 JQ2RVN]
[08/03 OVC]
最新トラックバック
ブログ内検索
最古記事
(05/18)
(05/19)
(05/19)
(05/20)
(05/21)
アクセス解析
|