初めて自分の家と他人の家が違う、と意識した時

マイコンにて、
C言語で浮動小数点の数値を表示するプログラムを作成しているのですが、

PRINT_OUT("123.456");
のように、文字列を直接指定した場合は正しく表示されるのですが、

sprintf()関数を用いて、浮動小数点を文字列に変換した場合、
buf char[10];
sprintf(buf,"%lf",123.456);
PRINT_OUT(buf);
とした場合はプログラムが暴走?(恐らく配列破壊を起こしていると
思われますが、)してしまい、上手く動作しません。
(但し、整数の場合は正常に動作します。)

そこで、質問させていただきたいのですが、
"123.456"のように直接文字列を指定した場合と、浮動小数点123.456
をsprintf()関数を用いて文字列に変換した"123.456"の書式に何か
違いはあるのでしょうか?よろしくお願い致します。

A 回答 (5件)

> sprintf(buf,"%lf",123.456);



まず、double型の書式指定は %lf ではなく %f です。
%lf を使った場合の動作は未定義ですので、何が起こっても不思議ではありません(C99対応の場合はOKです)。

また、PRINT_OUT関数の仕様が不明ですので、もしかするとそこに原因があるのかもしれません。

参考URL:http://www.kijineko.co.jp/tech/superstitions/pri …

この回答への補足

>>まず、double型の書式指定は %lf ではなく %f です。
>>%lf を使った場合の動作は未定義ですので、何が起こっても不思議では
>>ありません(C99対応の場合はOKです)。

そうだったのですね。%lfが標準だと勘違いしていました。
参考URLが参考になります。ありがとうございます。

>>また、PRINT_OUT関数の仕様が不明ですので、もしかすると
>>そこに原因があるのかもしれません。

PRINTOUT関数をもう少し調べてみます。

補足日時:2007/08/10 17:15
    • good
    • 0

H8ですね。

残念ながらルネサスはSH2とR8Cしか経験が無いんで経験からの話は出来なさそうです。
結果を見る限り、私もsprintfの浮動小数点の実装が心配ですね。
bufの内容を1バイトづつターミナルに表示させてみてはどうでしょう。
sprintf(buf,"%lf",123.456);
for( i=0; i<20 ; i++ ) {
char dump[10];
sprintf(dump,"%02x:%c\n",buf[i],buf[i]));
PRINT_OUT(dump);
}
こんな感じで。

この回答への補足

>>sprintf(buf,"%lf",123.456);
>>for( i=0; i<20 ; i++ ) {
>>char dump[10];
>>sprintf(dump,"%02x:%c\n",buf[i],buf[i]));
>>PRINT_OUT(dump);
>>}

bufの内容を1文字ずつ表示するこちらの方法も試してみたいと思います。
ご助言、ありがとうございます。

補足日時:2007/08/11 16:50
    • good
    • 0

おそらく暴走の原因は#2で指摘されている配列要素数の不足が原因でしょうね。


ただ、書式指定が間違っていると、本当に暴走してしまう実装も組み込みではときどき見かけます。また、sprintf関数自体がフリースタンディング環境ではサポートされないため、浮動小数点数が使えないことも普通にあったりします(浮動小数点周りのランタイムをリンクすると、非常にプログラムサイズが大きくなるので)。
その辺りも問題がないか調べてみてください。

PRINT_OUTに関しては、関数またはマクロの定義をよく調べることと、

char buf[] = "123.456";
PRINT_OUT(buf);

としたときに期待した結果になるかどうかを調べて、問題を切り分けることをお勧めします。

この回答への補足

>>ただ、書式指定が間違っていると、本当に暴走してしまう実装も
>>組み込みではときどき見かけます。また、sprintf関数自体がフリー
>>スタンディング環境ではサポートされないため、浮動小数点数が
>>使えないことも普通にあったりします(浮動小数点周りのランタイムを
>>リンクすると、非常にプログラムサイズが大きくなるので)。

そうですか。書式設定辺りに注意が必要そうですね。
また、確かにライブラリを読み込むとプログラムサイズが一気に大きくなりました。

>>char buf[] = "123.456";
>>PRINT_OUT(buf);

こちらの方法も試してみたいと思います。
ご助言、ありがとうございます。

補足日時:2007/08/11 16:45
    • good
    • 0

shirayukixさんへ。


マイコンですのでprintfは実装されていないか、特殊関数を用意しないと使えないと思います。
PRINT_OUT()がUARTを制御していてRS232Cの通信経由でターミナルソフトに文字列を表示する良くある仕組みだと思います。
暴走の原因は、shirayukixさんの言われる通り配列破壊で間違いないでしょう。

linuxbeginnerさんへ。
文字列は、文字列終端'\0'までを含んだ配列サイズを確保してください。
いちいち何文字か気にしているのが面倒であれば余裕を見たサイズで確保しましょう。
名前にLinuxとありますが、Linuxが乗るような32bitマイコンならメモリサイズの余裕があると思いますが。いや、その前にLinuxが乗っているならprintfぐらい使えるようになっているはずだから・・・。もっと小さいマイコンか?

この回答への補足

>>文字列は、文字列終端'\0'までを含んだ配列サイズを確保してください。いちいち何文字か気にしているのが面倒であれば余裕を見たサイズで確保しましょう。

 今後は、余裕を持たせて取ることにします。
しかし、今回、サイズを20に変更したのですが、暴走は止まりましたが、
PRINT_OUT()関数で全く表示がされませんので、PRINT_OUT()関数に原因がありそうです。
整数値なら正常に表示されるのが謎ですが。

>>名前にLinuxとありますが、Linuxが乗るような32bitマイコンなら
>>メモリサイズの余裕があると思いますが。いや、その前にLinuxが
>>乗っているならprintfぐらい使えるようになっている
>>はずだから・・・。もっと小さいマイコンか?

使用しているのはH3048という16[bit]のマイコンです。
名前には、Linuxとありますが、これはユーザ登録した当初はLinuxを使って
いたためであり、今回の質問の件とは関係がありません。ややこしくてすいません。

補足日時:2007/08/10 17:35
    • good
    • 0

%lfを使うと結果の小数点以下は6桁になります。


123.456000

sprintfでbufに格納すると末尾の'\0'を含めて11文字になりますからbufの長さ10文字を超えます。
なので配列破壊を起こしていると思います。

sprintfを使う前に、printfで出力してみてはどうでしょうか?

この回答への補足

>>%lfを使うと結果の小数点以下は6桁になります。
>>123.456000

>>sprintfでbufに格納すると末尾の'\0'を含めて11文字になりますから
>>bufの長さ10文字を超えます。なので配列破壊を起こしていると思います。

やはり、配列破壊の可能性が高そうですね。
bufのサイズを20に変更した所、暴走はなくなりましたが、
PRINT_OUT関数で全く表示がされていないようです。

>>sprintfを使う前に、printfで出力してみてはどうでしょうか?
これに関しては、マイコン上では、直接指定はできないのですが、
試しにWindows上で試してみたところ、正常に動作はしているみたいです。

補足日時:2007/08/10 17:17
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報