自作のprintf関数で%dの整数が出力できない

このQ&Aのポイント
  • H8S2368の基板で使用していなかったSCI0のUARTに新たに追加したprintf関数で整数が正しく出力されない問題が発生しています。
  • printf関数を使用して文字列を出力する場合は正常に動作していますが、整数を出力する場合は予期しない値が表示されます。
  • どのように改善すれば正しい整数値が出力されるようになるのか、アドバイスをいただきたいです。
回答を見る
  • ベストアンサー

自作のprintf関数で%dの整数が出力できない

前回、 http://okwave.jp/qa/q9193570.html こちらのサイトでH8S2368にprintfを追加したい内容の質問をした者で、その続きです。 現在H8S2368が搭載されている基板で使用していなかったSCI0のUARTを次のコードの void mprint_test_sci0(char *fmt, ...) この新たに追加したmprint_test_sci0というprintf関数で出力できるようになりました。 https://github.com/KenjiMaehara/ios_apply_test/blob/20150720_test/H8S2368_console/console/console.c しかし、 mprint_test_sci0("test value"); この場合”test value”という文字列がちゃんと出力できます。 しかし、 mprint_test_sci0("test value %d %d %d %x \n\r",1,2,3,4); この場合、 ”test value 65538 196612 900554 ff587e” このように、%dの整数値の部分が全然違う値で出力されてしまいます。 別のコードで mprint_test_sci0("test value %d %d %x %x \n\r",1,1,1,1); この場合は ”test value 65537 65537 dbdca ff587e” このように出力されます。 正しい整数値をこのmprint_test_sci0のprintf関数で出力するにはどのように改善したらよいか、ご教示頂きますよう、よろしくお願い致します。

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

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8524/19373)
回答No.3

unsigned long v; (略) v = (unsigned long)va_arg(args, long); switch (*p) { case 's': outs_sci0((char*)v, c); break; case 'c': outc_sci0((char)v, c); break; case 'd': case 'o': case 'x': outn_sci0(*p, v, c); } を char *vp; int vi; char vc; (略) switch (*p) { case 's': vp = (char *)va_arg(args, char *); outs_sci0(vp, c); break; case 'c': vc = (char)va_arg(args, char); outc_sci0(vc, c); break; case 'd': case 'o': case 'x': vi = (int)va_arg(args, int); outn_sci0(*p, vi, c); } にせんといかんよ。 何故なら mprint_test_sci0("test value %d %d %x %x \n\r",1,1,1,1); ってやると、可変引数の「1,1,1,1」は「16ビットのintが4つ渡される」から。 なお、%d、%o、%xは、今はint(16ビット幅。0~65535)までしか出力できないから char *vp; int vi; long vl; char vc; bool lf; (略) if (*p == '%') { lf = false; p++; if ((*p >= '1') && (*p <= '9')) { c = *p++ - '0'; while ((*p >= '0') && (*p <= '9')) c = c * 10 + (*p++ - '0'); } else if (*p == 'l') { p++; lf = true; } else c = -1; switch (*p) { case 's': vp = (char *)va_arg(args, char *); outs_sci0(vp, c); break; case 'c': vc = (char)va_arg(args, char); outc_sci0(vc, c); break; case 'd': case 'o': case 'x': if (lf) { vl = (long)va_arg(args, long); outn_sci0(*p, vl, c); } else { vi = (int)va_arg(args, int); outn_sci0(*p, vi, c); } } とか、新たに「longバージョンの%ld、%lo、%lx」とか作って、呼び出す際に mprint_test_sci0("test value %d %ld %x %lx \n\r",1,1L,1,1L); とやって「可変引数に渡した数字はlongであることを明記」してやれば、long型も使える筈。 なお、この改造は「デバッグしてない」ので、バグっているかもしれない。 プログラムを直さないで、今のまま使うなら mprint_test_sci0("test value %d %d %x %x \n\r",1L,1L,1L,1L); とか mprint_test_sci0("test value %d %d %x %x \n\r",(long)a,(long)b,(long)(a + 4),(long)(a + b)); とかって感じで「数値の引数は必ずlongで渡す」ってやれば良い。

techhouse
質問者

お礼

回答頂きありがとうございます。 詳細なサンプルコード頂き大変助かります。 コードを参考にさせて頂き、修正しました。 https://github.com/KenjiMaehara/ios_apply_test/blob/20150720_test/H8S2368_console/console/console.c 次のように"mprint_test_sci0"での出力結果で数値が出るようになりました。 (コード例) mprint_test_sci0("test test3: %d %d %d %x \n\r",1,1,1,1); mprint_test_sci0("test test4: %d %d %d %x \n\r",1,2,3,4); mprint_test_sci0("test test5:"); for(k=0;k<16;k++) { mprint_test_sci0("%d,",k); } mprint_test_sci0("\n\r"); mprint_test_sci0("test test6:"); for(k=0;k<16;k++) { mprint_test_sci0("%x,",k); } mprint_test_sci0("\n\r"); (出力結果) test test3: 1 1 1 1 test test4: 1 2 3 4 test test5:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, test test6:0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,

その他の回答 (3)

  • tadys
  • ベストアンサー率40% (856/2135)
回答No.4

確かめていないので間違えているかもしれませんが、次のように確認してください。 mprint_test_sci0("test value %d %d %d %x \n\r",1,2,3,4);の部分を次のように変えてテストして見てください。 double a=1.0; double b=2.0; double c=3.0; int x=4; mprint_test_sci0("test value %d %d %d %x \n\r",a,b,c,x); たぶんこれで希望通りに出力されるでしょう。 これでよかったら、次を確認してください。 mprint_test_sci0("test value %d %d %d %x \n\r",(double)1,(double)2,(double)3,4); これもうまくいくでしょう。 可変引数を持つ関数の場合コンパイル時に引数の型チェックを行うことが出来ないので型が合わない記述をしてもコンパイルエラーが出ません。 こちらを参考に http://blog.kazuhooku.com/2014/12/c.html 一度、使用している開発環境で使用している変数のサイズがどうなっているのか、関数の引数がどのような形で渡されているのかを調べておくのが良いです。 私が経験した者にはdoubleとfloatが同じサイズだったり、charとintが16ビットだったりするものが有りました。

techhouse
質問者

お礼

回答頂きありがとうございます。 サンプルコード頂き大変助かります。 コードを参考にさせて頂き、修正しました。 https://github.com/KenjiMaehara/ios_apply_test/blob/20150720_test/H8S2368_console/console/console.c 次のように"mprint_test_sci0"での出力結果で数値が出るようになりました。 (コード例) mprint_test_sci0("test test3: %d %d %d %x \n\r",1,1,1,1); mprint_test_sci0("test test4: %d %d %d %x \n\r",1,2,3,4); mprint_test_sci0("test test5:"); for(k=0;k<16;k++) { mprint_test_sci0("%d,",k); } mprint_test_sci0("\n\r"); mprint_test_sci0("test test6:"); for(k=0;k<16;k++) { mprint_test_sci0("%x,",k); } mprint_test_sci0("\n\r"); (出力結果) test test3: 1 1 1 1 test test4: 1 2 3 4 test test5:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, test test6:0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,

  • trapezium
  • ベストアンサー率62% (276/442)
回答No.2

va_arg() の使い方がおかしくないですか? > v = (unsigned long)va_arg(args, long); じゃなく、それぞれの型に合わせて取り出さないと、 outs_sci0((char*)va_arg(args, char *), c); outn_sci0(*p, (unsigned long)va_arg(args, int), c); みたいに。 こういう汎用ルーチンは他のテストしやすい環境でテストしてみてもいいです。実際の文字出力のとこはラップしておく必要はありますが。

techhouse
質問者

お礼

回答頂きありがとうございます。 詳細なサンプルコード頂き大変助かります。 コードを参考にさせて頂き、修正しました。 https://github.com/KenjiMaehara/ios_apply_test/blob/20150720_test/H8S2368_console/console/console.c 次のように"mprint_test_sci0"での出力結果で数値が出るようになりました。 (コード例) mprint_test_sci0("test test3: %d %d %d %x \n\r",1,1,1,1); mprint_test_sci0("test test4: %d %d %d %x \n\r",1,2,3,4); mprint_test_sci0("test test5:"); for(k=0;k<16;k++) { mprint_test_sci0("%d,",k); } mprint_test_sci0("\n\r"); mprint_test_sci0("test test6:"); for(k=0;k<16;k++) { mprint_test_sci0("%x,",k); } mprint_test_sci0("\n\r"); (出力結果) test test3: 1 1 1 1 test test4: 1 2 3 4 test test5:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, test test6:0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,

  • trytobe
  • ベストアンサー率36% (3457/9591)
回答No.1

昔ながらの FILE構造体としてストリームを準備して、fprintf 関数でそのストリームに流し込むようにしていないから、printf の表示形式指定の構文解析機能まで実装しないといけなくなっているだけ、ではありませんか。 fprintf FILE stdout stdprn - Google 検索 https://www.google.co.jp/search?q=fprintf+FILE+stdout+stdprn つまり、昔プリンタドライバに FILE *stdprn へ fprintf していたように、FILE *sci0 を準備すべくドライバを書くほうが printf でも puts でも putchar でも最下層レベルでサポートできる。

techhouse
質問者

お礼

回答頂きありがとうございます。 詳細なサンプルコード頂き大変助かります。 コードを参考にさせて頂き、修正しました。 https://github.com/KenjiMaehara/ios_apply_test/blob/20150720_test/H8S2368_console/console/console.c 次のように"mprint_test_sci0"での出力結果で数値が出るようになりました。 (コード例) mprint_test_sci0("test test3: %d %d %d %x \n\r",1,1,1,1); mprint_test_sci0("test test4: %d %d %d %x \n\r",1,2,3,4); mprint_test_sci0("test test5:"); for(k=0;k<16;k++) { mprint_test_sci0("%d,",k); } mprint_test_sci0("\n\r"); mprint_test_sci0("test test6:"); for(k=0;k<16;k++) { mprint_test_sci0("%x,",k); } mprint_test_sci0("\n\r"); (出力結果) test test3: 1 1 1 1 test test4: 1 2 3 4 test test5:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, test test6:0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,

関連するQ&A

  • printf()で出力したいんですが?

    #include <stdio.h> int main( void ) { int air[4]; int i; i = 0; printf( "データ入力\n" ); do{ scanf( "%d\t", &air[ i++ ]); } while(air[ i - 1 ] > 0 ); printf( "%d\n", i ); return 0; } このプログラムはコンパイル出来ますが、期待していたprintf関数での出力ができません。 その理由として何がありますか?関数の使い方が間違っているのか、DO~WHILE文が使えない場所 なのか、もし直すとすればどう直せばいいのですか。

  • H8Sマイコンでprintfを複数ポートで使いたい

    現在H8S2368マイコンを搭載した基板のプログラムのデバッグなどを行っています。 このボードではマイコンのUARTのSCI1をRS-232Cポートとして使用しており、外部ユニットに接続したりデバッグ時にはプログラム内にデバッグ用に設置したprintfのキャラクタ出力用のポートとして使用しています。 現在UARTのSCI0ポートが未使用の状態で、このポートにWiFiモジュールのESP-WROOM-02を接続したいと考えております。 WiFiモジュールのESP-WROOM-02との通信はSCI0ポートを介するのでプログラミングではprintf関数を使うと思うのですが、現在printf関数で書かれたコードはSCI1ポート専用となっているのですが、 printf関数使用時にSCI0で出力するのか、SCI1で出力するのかを選択するにはどのようにプログラムしたらよいのでしょうか? なお、printfに関するプログラムはプロジェクト内のこれらのファイルで設定しています。 console.c lowsrc.c iodefine.h console.c内で宣言した”charput”、”charget”はlowsrc.cでしようされています。 どうぞ、ご教示の程よろしくお願い致します。 ------------------------(iodefine.hの内容)------------------------------------------------- #define CONSOLE_P SCI1 #define _CONSOLE_P _SCI1 -------------------------------------------------------------------------------------------------- -------------------------(console.cの内容)-------------------------------------------------- char charget(void); void charput(char); void PutStr(char *); #ifdef CONSOLE_DEBUG char charget(void) { char InputChar; while (CONSOLE_P.SSR.BIT.RDRF == 0) { /* ignore errors */ if ((CONSOLE_P.SSR.BYTE & ORER_FER_PER) != 0x00) CONSOLE_P.SSR.BYTE &= ~ORER_FER_PER; } InputChar = CONSOLE_P.RDR; CONSOLE_P.SSR.BIT.RDRF = 0; charput(InputChar); return (InputChar); } void charput(char OutputChar) { while ((CONSOLE_P.SSR.BIT.TDRE) == 0); CONSOLE_P.TDR = OutputChar; CONSOLE_P.SSR.BIT.TDRE = 0; } void charput_sci1(char OutputChar) { while ((CONSOLE_P_SCI1.SSR.BIT.TDRE) == 0); CONSOLE_P_SCI1.TDR = OutputChar; CONSOLE_P_SCI1.SSR.BIT.TDRE = 0; } void PutStr(char *str) { while (*str != '\0') charput(*str++); } #else char charget(void) { } void charput(char OutputChar) { } void PutStr(char *str) { } #endif --------------------------------------------------------------------------------------------------

  • printfだと出力されるのにfprintfだと出力されないのはなぜですか?

    今プログラムを作りかけなのですが、 forで何回もまわして計算しているので printfでそのまま出力すると見づらくなってきたので テキストに出力したくてちょっといじってみたんですが、テキストは作成されるんですが肝心の数字が出力されていません。 ソースのいじったところは pritf("s[%d]=%f\n",a,b); となっていたところを メイン分の最初で FILE *fp; を宣言して fp=fopen("test.txt","w"); 省略 fpritf(fp,"s[%d]=%f\n",a,b); と直しただけなのですが test.txtに何も書き込まれません。 ソースを省略しすぎかもしれませんが よろしくおねがいします。

  • printf、最大値の出し方

    3つの整数を入力し、どれが最大値かを判別するプログラムを作りたいです。 #include<stdio.h> main() { int i, x, max; max = 0; i = 1; while(i <= 3) { printf("整数:"); scanf("%d",&x); if (x > max) { max = x; } i++; } printf("最も大きい整数は%d\n", max); } とすると 整数:と3回表示されますが、これを一つ目の整数:、二つ目の整数:3つ目の整数:と表示されるようなプログラムにするにはどうしたらよいでしょうか。

  • H8Sマイコンに新規printfを追加でエラー

    前回、 http://okwave.jp/qa/q9191153.html こちらのサイトでH8S2368にprintfを追加したい内容の質問をした時の続きです。 現在、 イチから作って丸ごと学ぶ! H8マイコン道(12):シリアル通信でオリジナルprintf関数を作ろう (3/3) - MONOist(モノイスト) http://monoist.atmarkit.co.jp/mn/articles/1003/26/news096.html こちらのサイトの内容を参考に、printfのサンプルコードを追加してみました。 https://github.com/KenjiMaehara/ios_apply_test/blob/20150720_test/H8S2368_console/console/console.c しかし、コード追加後にコンパイルを実施すると次のようなエラーが発生します。 (コンパイルエラー内容) HMAKE MAKE UTILITY Ver. 2.1.00.000 Copyright (C) 2001,2006 Renesas Technology Europe Ltd. Copyright (C) 2001,2006 Renesas Technology Corp. and Renesas Solutions Corp. Executing Hitachi H8S,H8/300 C/C++ Library Generator01 phase set CH38TMP=C:\Users\KMAEH_~1\AppData\Local\Temp set PATH=c:\program files (x86)\renesas\hew\tools\renesas\h8\6_2_2\bin set CH38=c:\program files (x86)\renesas\hew\tools\renesas\h8\6_2_2\include Executing Hitachi H8S,H8/300 C/C++ Compiler02 phase "c:\program files (x86)\renesas\hew\tools\renesas\h8\6_2_2\bin\ch38.exe" -ws=C:\Users\KMAEH_~1\AppData\Local\Temp\hmk6689.tmp Executing Hitachi H8S,H8/300 Assembler03 phase Executing Hitachi OptLinker04 phase "c:\program files (x86)\renesas\hew\tools\renesas\h8\6_2_2\bin\LnkSpawn.exe" -subcommand=C:\Users\KMAEH_~1\AppData\Local\Temp\hmk6A82.tmp ** L2310 (E) Undefined external symbol "_mprint_test_sci1" referenced in "..\myproject\obj\main.obj" Optimizing Linkage Editor Abort ERROR: Process failed with return code: 1 mprint_test_sci1という関数の宣言は #include "all_includes.h" こちらのヘッダーファイルに (all_includes.hの内容の一部) extern void outs_sci1(char *, short); extern void outc_sci1(char, short); extern void outn_sci1(char, unsigned long, short); extern void mprint_test_sci1(char *fmt, ...); extern void charput_sci1(char OutputChar); このような形で宣言しています。 しかし、エラーが出てくるのですが、これをどのように解決すればよいのかご教示頂きますよう、よろしくお願い致します。

  • 関数の戻り値として文字列を返して、printfで出力させることはできますか?

    いま、引数の数値によって、文字列を返すという関数を作り、それをprintf関数で出力したいと考えているんですが、どうやって作ればいいのかわかりません。 char data_2_dtmfdata(u8 getdata) { switch(getdata) { case 0x01: //tone"1" return "KEY_1"; case 0x02: //tone"2" return "KEY_2"; case 0x03: //tone"3" return "KEY_3"; } } このような感じで関数を作成して、 printf("%s",data_2_dtmfdata(data)); printf関数でこのように設定してあげれば”KEY_1”とか”KEY_3”とかの文字列を出力してあげられるのでしょうか?

  • NSString文字列をprintfで出力するには

    Objective-CでNSStringクラスの文字列をprintf関数で出力しようとするとコンパイルエラーになります。 どうすればprintfで出力できるようになるでしょうか。 実行環境はMacOSX。Xcodeをインストールしています。 ソースコードとエラーメッセージは以下です。 #import <Foundation/NSObject.h> #import <stdio.h> int main(void){ NSString *str01 = @"test"; printf("%s\n", [str01 UTF8String]); return 0; } <コンパイルエラーメッセージ> warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘id’

  • printfで0x600000番地の次の0x600001番地の値を出力したい。

    H8マイコンの0x600000番地につながるSRAMメモリの内容を見たくて、 #define SRAM_BASE_ADDR 0x600000 #define SRAM_TEST_ADDR *((volatile u8 *)SRAM_BASE_ADDR) printf("data:%X addr:%p\n\r", SRAM_TEST_ADDR,(void*)&SRAM_TEST_ADDR); このような形でアドレス0x600000番地のデータをprintf関数で出力してUARTで確認していたのですが、次の0x600001番地のデータをみたい場合はprintf関数をどのように書いたらよいのでしょうか?

  • 自作関数について

    下記の時、関数copyを作成したいのですが、 関数copyにその都度、違う引数を渡たす為には どうしたら良いのでしょうか? 教えてください。 #include <stdio.h> void main() {      char a[20]={"ABCDEF"}; char b[20]; copy(a,b); printf("%s\n",b); copy(a,&a[3]); printf("%s\n",buf); copy(&b[2],dat[5]); printf("%s\n",dat); }

  • printfの出力について

    初歩的な事ですが、 short *a; short b; a = &b; printf("%04x\n",x++); だとどのように出力されるのですか? 本を読むと、4つの幅をもたせて16進数で表すと思うのですが、 実行してもよくわからないのでよろしければ教えてください。 bのアドレスは、0x1234としておきます。

専門家に質問してみよう