• ベストアンサー

sprintf関数での文字列変換について

マイコンにて、 C言語で浮動小数点の数値を表示するプログラムを作成しているのですが、 PRINT_OUT("123.456"); のように、文字列を直接指定した場合は正しく表示されるのですが、 sprintf()関数を用いて、浮動小数点を文字列に変換した場合、 buf char[10]; sprintf(buf,"%lf",123.456); PRINT_OUT(buf); とした場合はプログラムが暴走?(恐らく配列破壊を起こしていると 思われますが、)してしまい、上手く動作しません。 (但し、整数の場合は正常に動作します。) そこで、質問させていただきたいのですが、 "123.456"のように直接文字列を指定した場合と、浮動小数点123.456 をsprintf()関数を用いて文字列に変換した"123.456"の書式に何か 違いはあるのでしょうか?よろしくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.1

> sprintf(buf,"%lf",123.456); まず、double型の書式指定は %lf ではなく %f です。 %lf を使った場合の動作は未定義ですので、何が起こっても不思議ではありません(C99対応の場合はOKです)。 また、PRINT_OUT関数の仕様が不明ですので、もしかするとそこに原因があるのかもしれません。

参考URL:
http://www.kijineko.co.jp/tech/superstitions/printf-format-for-double
linuxbeginner
質問者

補足

>>まず、double型の書式指定は %lf ではなく %f です。 >>%lf を使った場合の動作は未定義ですので、何が起こっても不思議では >>ありません(C99対応の場合はOKです)。 そうだったのですね。%lfが標準だと勘違いしていました。 参考URLが参考になります。ありがとうございます。 >>また、PRINT_OUT関数の仕様が不明ですので、もしかすると >>そこに原因があるのかもしれません。 PRINTOUT関数をもう少し調べてみます。

その他の回答 (4)

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.5

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); } こんな感じで。

linuxbeginner
質問者

補足

>>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文字ずつ表示するこちらの方法も試してみたいと思います。 ご助言、ありがとうございます。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

おそらく暴走の原因は#2で指摘されている配列要素数の不足が原因でしょうね。 ただ、書式指定が間違っていると、本当に暴走してしまう実装も組み込みではときどき見かけます。また、sprintf関数自体がフリースタンディング環境ではサポートされないため、浮動小数点数が使えないことも普通にあったりします(浮動小数点周りのランタイムをリンクすると、非常にプログラムサイズが大きくなるので)。 その辺りも問題がないか調べてみてください。 PRINT_OUTに関しては、関数またはマクロの定義をよく調べることと、 char buf[] = "123.456"; PRINT_OUT(buf); としたときに期待した結果になるかどうかを調べて、問題を切り分けることをお勧めします。

linuxbeginner
質問者

補足

>>ただ、書式指定が間違っていると、本当に暴走してしまう実装も >>組み込みではときどき見かけます。また、sprintf関数自体がフリー >>スタンディング環境ではサポートされないため、浮動小数点数が >>使えないことも普通にあったりします(浮動小数点周りのランタイムを >>リンクすると、非常にプログラムサイズが大きくなるので)。 そうですか。書式設定辺りに注意が必要そうですね。 また、確かにライブラリを読み込むとプログラムサイズが一気に大きくなりました。 >>char buf[] = "123.456"; >>PRINT_OUT(buf); こちらの方法も試してみたいと思います。 ご助言、ありがとうございます。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.3

shirayukixさんへ。 マイコンですのでprintfは実装されていないか、特殊関数を用意しないと使えないと思います。 PRINT_OUT()がUARTを制御していてRS232Cの通信経由でターミナルソフトに文字列を表示する良くある仕組みだと思います。 暴走の原因は、shirayukixさんの言われる通り配列破壊で間違いないでしょう。 linuxbeginnerさんへ。 文字列は、文字列終端'\0'までを含んだ配列サイズを確保してください。 いちいち何文字か気にしているのが面倒であれば余裕を見たサイズで確保しましょう。 名前にLinuxとありますが、Linuxが乗るような32bitマイコンならメモリサイズの余裕があると思いますが。いや、その前にLinuxが乗っているならprintfぐらい使えるようになっているはずだから・・・。もっと小さいマイコンか?

linuxbeginner
質問者

補足

>>文字列は、文字列終端'\0'までを含んだ配列サイズを確保してください。いちいち何文字か気にしているのが面倒であれば余裕を見たサイズで確保しましょう。  今後は、余裕を持たせて取ることにします。 しかし、今回、サイズを20に変更したのですが、暴走は止まりましたが、 PRINT_OUT()関数で全く表示がされませんので、PRINT_OUT()関数に原因がありそうです。 整数値なら正常に表示されるのが謎ですが。 >>名前にLinuxとありますが、Linuxが乗るような32bitマイコンなら >>メモリサイズの余裕があると思いますが。いや、その前にLinuxが >>乗っているならprintfぐらい使えるようになっている >>はずだから・・・。もっと小さいマイコンか? 使用しているのはH3048という16[bit]のマイコンです。 名前には、Linuxとありますが、これはユーザ登録した当初はLinuxを使って いたためであり、今回の質問の件とは関係がありません。ややこしくてすいません。

回答No.2

%lfを使うと結果の小数点以下は6桁になります。 123.456000 sprintfでbufに格納すると末尾の'\0'を含めて11文字になりますからbufの長さ10文字を超えます。 なので配列破壊を起こしていると思います。 sprintfを使う前に、printfで出力してみてはどうでしょうか?

linuxbeginner
質問者

補足

>>%lfを使うと結果の小数点以下は6桁になります。 >>123.456000 >>sprintfでbufに格納すると末尾の'\0'を含めて11文字になりますから >>bufの長さ10文字を超えます。なので配列破壊を起こしていると思います。 やはり、配列破壊の可能性が高そうですね。 bufのサイズを20に変更した所、暴走はなくなりましたが、 PRINT_OUT関数で全く表示がされていないようです。 >>sprintfを使う前に、printfで出力してみてはどうでしょうか? これに関しては、マイコン上では、直接指定はできないのですが、 試しにWindows上で試してみたところ、正常に動作はしているみたいです。

関連するQ&A

  • 浮動小数点から文字列の変換の時に

    浮動小数点floatからStrへの変換をgcvt関数で行なうときに、値が小さいと文字列0.00005が欲しいのに5e-05になってしまいます。 どうすればよいですか?教えてください。

  • atof関数って何ですか?

    参考書などを見ると文字列を浮動小数点数(double)に変換するには、atof関数を使いますって書いてあるんですが、文字列を浮動小数点数(double)に変換するってどういう意味ですか? 回答よろしくお願いします。

  • 文字列変換プログラムのポインタについて

    いかの関数は、文字列を16進文字列に変換する関数です。過去の質問を参考に自分で作りました。 動作することはするんですが、よく見るとpoとpiは領域確保していません。これってプログラム上まずいでしょうか。 char *conv( char *buff, char *str ) {   char *po;   char *pi;   for(po=buff, pi=str; *pi; pi++)   {     if(0 <= *pi && *pi <= 15)     {       sprintf(po, "%x", 0);       po++;       sprintf(po, "%x", *pi);       po++;     }else {       sprintf(po, "%x", (0x0f & (*pi >> 4)));       po++;       sprintf(po, "%x", (0x0f & (*pi % 16)));       po++;     }   }   *po='\0';   return(buff); }

  • H8/3052 クロスコンパイラ環境下でのsprintfの使用について

    実務訓練でH8を用いて測定システムを開発しています。 今、H8に接続したセンサの値を測定しA/D変換した値を、フーリエ変換し、その結果をシリアル通信のソフト(ハイパーターミナル)などで表示できるようするために、その値を文字コードに変換して送るようにしているところです。 その変換した値がどのくらいなのかわからないので、場合わけ等が必要なのかと思っていましたら、会社の方にsprintfを使えばいいと言われました。 それは気づかなかったと思って、使ってみたら動きませんでした(^^; 型のあわせ方とかが間違っているのかな? char buf[100]; sprintf(buf,"%f",a[k]); //a[k]はフーリエ展開した係数の値(double) for(i=0;i<100;i++){ SCI_OUT_d(buf[i]); //SCI_OUT_dはシリアル送信関数 } なにかおかしいところありますか? ためしに char buf[100]; float DFTa; DFTa=(float)a[k]; sprintf(buf,"%f",a[k]); //a[k]はフーリエ転換した係数の値(double) for(i=0;i<100;i++){ SCI_OUT_d(buf[i]); //SCI_OUT_dはシリアル送信関数 } でfloat型にしてみてもそこでとまってしまいました。 何かH8のsprintfの実装についてわかることがある人がいましたら回答お願いします。

  • 文字列を文字コードの数値に変換する方法

    JISコードの日本語を含む文字列を、文字コードの数値に変換する方法がわからなくて困っています。とりあえずは文字列ではなく、1文字だけ変換することを目指してord関数を使ったんですが、1バイト文字はうまくいったのですが、2バイト文字だと思うような結果になりませんでした。 例)以下のように変換したいです。 「a」→「97」 「あ」→「9250」 どなたかいい方法や関数をご存じないでしょうか? ちなみに下記のように片っ端から試してみたのですが、思うような結果が得られませんでした。 $buf = mb_convert_encoding($_POST["string"], "JIS", "EUC-JP"); $jis_code1 = ord("$buf"); $jis_code2 = bin2hex("$buf"); $jis_code3 = urlencode("$buf"); $jis_code4 = intval("$buf");

    • 締切済み
    • PHP
  • C言語のsprintfに相当する関数をご存知でしたら教えて下さい。

    初めてjavaでプログラムを作成しています。 C言語のsprintfに相当するような書式文字列が扱える関数をご存知でしたら教えて下さい。 宜しくお願いします。

  • sprintfを用いたフォーマット文字列攻撃

    sprintfを用いたフォーマット文字列攻撃に関する質問です。 main文の中で --------------------- int main(void){ char str[50]; sprintf(str,"%s"); puts(str); } --------------------- を実行すると(null)で帰ってきます。 しかし関数呼び出しを行うと結果が変わってきます。 --------------------- void f(){ char str[50]; sprintf(str,"%s"); puts(str); } int main(void){ f(); } --------------------- これを実行すると" ・L "のような文字化けしたものに変わりました。 sprintf(str,"%s%s");と記述することによって" ・L (null) "と、本来呼び出される箇所のものが格納されています。 なぜ関数呼び出しにすると変なところを参照してしまうのか(第3引数があると勘違いしてしまうのか)教えてください。 また、これによりどのような悪影響があるのか教えてください。 自分はプログラマが意図しない箇所を参照するため攻撃者のプログラムアドレスを格納してしまう恐れがあると考えています。

  • sprintf

    文字列に1文字を結合したいんだけど、 例えば  char str[] = "xy";  char c = 'z'; があって、2つを結合する場合、 #include <iostream.h> main(){  char str[] = "xy";  char c = 'z';  char buf[2];  buf[0] = c;  buf[1] = 0;  strcat(str, buf);  cout << str; } でもいいけど、もっと簡単にする方法があったら教えてください。  char str[] = "xy";  char c = 'z';  sprintf(str, "%s%c\0", str, c);  cout << str; イメージ的にこうだけど、失敗しました。

  • 文字列変換マクロ

    小数点以下5桁(B列)をC列に文字列として変換したいです。 (B列は3.62%入力で表示形式をパーセンテージの小数点以下5桁で表示) データ量が多いためVBA作成希望です。どなたか教示お願いします。

  • 文字列連結演算子と浮動小数点型

    本に 「文字列型連結演算子では浮動小数点型等の出力形式を指定できません。出力をフォーマットしたい場合はprintf関数を利用する」 と記載されていますが、これ以上の詳しい説明が記載されていないので、それがちょっと分かりません。分かる方は教えてください。 私の仮定では、 --------------------------------------------- <?php $a=1.23; $b=1.23; print $a.$b //文字列連結演算子で$aと$bを繋ぐ。 ?> --------------------------------------------- 出力結果は1.231.23となる。それを回避するために --------------------------------------------- <?php $a=1.23; $b=1.23; printf("%f",$a.$b) //printf関数を使って出力をフォーマット ?> --------------------------------------------- 出力結果は1.231000となりますが、その解釈で正しいでしょうか。

    • ベストアンサー
    • PHP

専門家に質問してみよう