• ベストアンサー

va_list型について

あるC言語のソースを見ていたら、va_list型の引數を持つ函數がありました。 そのソースは複雜なので、質問するために以下のソースを作りました。 (ですから、このプログラムはじつよう性もないし、無意味なこともしています。) #include <stdio.h> #include <stdarg.h> int sum_func1(int sw1, va_list ap1) { int sum1 = 0; va_start(ap1, sw1); sum1 += va_arg(ap1,int); sum1 += va_arg(ap1,int); va_end(ap1); return(sum1); } int sum_func0(int sw0, ...) { int sum0; va_list ap0; int a0, b0; va_start(ap0, sw0); a0=va_arg(ap0, int); b0=va_arg(ap0, int); printf("sum_func0です。これから%dと%dを足します。\n", a0, b0); sum0 = sum_func1(sw0, ap0); va_end(ap0); return(sum0); } int main(void) { printf("1 + 2 = %d\n", sum_func0(0,1,2)); return 0; } やっていることは、結局のところ、1と2を足してその結果を表示しているだけです。 このプログラムは動かすことはできますが、表示される足し算の結果がおかしいです。 sum_func0の中で 1(a0)と2(b0)は既にva_argを使って取得しています。 その後、sum_func1の中で、再び この1と2を取得しようとしているのですが、 このようなことは可能でしょうか。 可能ならば、どのように修整すればよいのでしょうか。 これが可能か否かが元のソースの讀み方に影響するのです。 最初に述べたように、va_list型の引數を持つ函數についての質問なので、 va_list型の引數を使わないような修整方法ですと、 期待するものではありません。

noname#2823
noname#2823

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

  • ベストアンサー
  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.3

あと、sum_func1のなかの、va_start、va_endも不要ですね。

noname#2823
質問者

お礼

No2、No3 これはおもしろいですね。 もちろん、回答としては正解です。 これも單純化すると、次のような仕組みになっているんですね。 int sum_func0(int sw0, ...) { va_list ap0,ap1; va_start(ap0, sw0); ap1=ap0; va_arg(ap0, int); va_arg(ap0, int); va_arg(ap1, int); va_arg(ap1, int); va_end(ap0); ・ ・ } va_list型の變數が2つあるのがポイントですね。 これもap1から引數を取り出す部分を函數にすれば、質問に適しますね。

その他の回答 (2)

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.2

>va_start(ap0, sw0); >a0=va_arg(ap0, int); >b0=va_arg(ap0, int); va_argマクロは、ap0の内容を書き換えます。 そのため、sum_func1に正しい引数がわたっていません。 va_list ap0, ap1; va_start(ap0, sw0); ap1 = ap0; ・ ・ ・ sum0 = sum_func1(sw0, ap1); とすればsum_func1()で問題なく呼び元からの可変引数を利用できます。

  • e101tre
  • ベストアンサー率38% (7/18)
回答No.1

> sum_func0の中で 1(a0)と2(b0)は既にva_argを使って取得しています。 > その後、sum_func1の中で、再び この1と2を取得しようとしているのですが、 > このようなことは可能でしょうか。 va_start ~ va_end で囲めば、何回でも取得できるはずです。 以下に例を示します。 //int sum_func1(int sw1, va_list ap1) int sum_func1(va_list ap1) { int sum1 = 0; //va_start(ap1, sw1); sum1 += va_arg(ap1,int); sum1 += va_arg(ap1,int); //va_end(ap1); return(sum1); } int sum_func0(int sw0, ...) { int sum0; va_list ap0; int a0, b0; va_start(ap0, sw0); a0=va_arg(ap0, int); b0=va_arg(ap0, int); printf("sum_func0です。これから%dと%dを足します。\n", a0, b0); //sum0 = sum_func1(sw0, ap0); va_end(ap0); va_start(ap0, sw0); sum0 = sum_func1(ap0); va_end(ap0); return(sum0); }

noname#2823
質問者

お礼

なるほど~、と思いました。 ありがとうございました。 これは單純化して可變數個引數關係のみを拔き出して書くと、 次のように、va_start、va_endの組が、【入れ子にならずに】ならんでいますね。 int sum_func0(int sw0, ...) { va_list ap0; va_start(ap0, sw0); a0=va_arg(ap0, int); b0=va_arg(ap0, int); va_end(ap0); va_start(ap0, sw0); a0=va_arg(ap0, int); b0=va_arg(ap0, int); va_end(ap0); } あとは2番目の「va_start・va_endの組」の内側が、 va_list型ap0を引數とする函數になっているだけですね。 ご回答が私の質問に對して正解であるのは言うまでもないですが、 私の疑問は入れ子にすることはできないのだろうか、 ということでした。

関連するQ&A

  • gcc: incompatible pointer type

    以下のCソースでコンパイルすると、warning: passing arg 1 of `func_b' from incompatible pointer type となります。 void (*p_func)() は、引数を省略しているので int として扱われるということでしょうか? #include <stdio.h> #include <stdlib.h> void func_a( unsigned char x ){ printf( "x=%d\n", x ) ; } void func_b( void (*p_func)() ){ p_func( 1 ) ; } int main(){ func_b( func_a ) ; return 0 ; }

  • 関数のパラメータを配列に格納したいのですが

    #include<stdio.h> #include<stdlib.h> int func(int, int, int, int); int main(void) { int a = 3, b = 4, c = 5, d = 6; int sum; sum = func(a, b, c, d); printf("合計は%dです。\n", sum); return EXIT_SUCCESS; } int func(int m, int n, int o, int p) { int Hairetu[4]; int Sum = 0; int i; /* ここで、Hairetuにm, n, o, pを格納したい */ for(i=0; i<4; i++) Sum += Hairetu[i]; return Sum; } 例えばこのようなプログラムがあった時、m, n, o, pの値をHairetuに格納するには、どのようにすればよいのでしょうか。 分かりにくい文章ですが、どうかよろしくお願い致します。

  • 一行で再帰関数と3項演算子で合計値を出したいです。

    以下のソースで、3項演算子を使い、int tmp;は使わずに1行でreturnすることはできますか? 教えてください。 よろしくお願いします。 #include<stdio.h> int Sum(int *num,int cnt) { if(cnt==0){return 0;} int tmp=*num; return tmp+Sum(++num,cnt-1); } int main() { int List[5]; List[0]=1; List[1]=10; List[2]=100; List[3]=1000; List[4]=8889; printf("%d",Sum(List,sizeof(List)/sizeof(int))); getchar(); return 0; }

  • 可変長引数を実現する va系

    今、可変長引数をBUFFERにいれて 送る(SSLを使いますが・・・)ことをしていますが、 どうしてもその部分らしいところでwarningがでます。 どうもいまいちva系の取り扱いがわからないので、 アドバイスいただけるとうれしいです。 ****ソース(va系が含まれるところのみ)**** WriteToClient (fmt, va_alist) char *fmt; va_dcl { va_list ap; char * ssl_buf[1024]; va_start (ap); vfprintf (stdout, fmt, ap); va_end (ap); //SSL SSL_write(ssl, ssl_buf, sizeof(ssl_buf) ); } *****コンパイル後のwarningメッセージ**** /usr/local/lib/gcc-lib/i386-pc-solaris2.8/2.95.3/include/stdarg.h:96: warning: ` va_start' redefined /usr/local/lib/gcc-lib/i386-pc-solaris2.8/2.95.3/include/varargs.h:111: warning: this is the location of the previous definition SSLpasschanger.c:216: macro `va_start' used with just one arg わかる方いらっしゃいましたら、よろしくおねがいいたします。

  • va_listを使用したfscanf()関数のラッパー関数

    【環境】WinXP/VC++6.0/Win32コンソールアプリ 初めて質問させていただきます。 テキストファイル入出力クラスを作成中で、書式指定付きの読込み関数を次のように定義しています。 CTextFileIO::Read(LPCSTR lpFormat,...) {   va_list arg;   va_start(arg,lpFormat);   fscanf(this->hFile,lpFormat,arg);   va_end(arg); } hoge.txtの内容 5 使用する場合 void main() {   int i;   CTextFileIO file("hoge.txt");   // ☆読込み   file.Read("%d",&i);   // i に 5 が読込まれることを期待している。   printf("%d",i); } 実行結果 -858993460 ご質問は、☆の箇所でどうして i に 5 が取得できないのかということです。同様の作り方で出力関数 vfprintf() のラッパー関数を試した場合は正しく動作しました。 以上よろしくお願いいたします。

  • 可変引数をconstで参照渡し

    以下のようなクラスをconstの参照渡しでうけとる、可変引数を持つ関数を作りたいのですが、以下のようにしてもうまくいきません。 何か良い方法はないものでしょうか? template<class TT> class vector3{ public:  enum{NUM=3};  TT x[NUM];  void Sum(const int num,...); }; template<class TT> void vector3<TT>::Sum(const int num,const ...){  int i,j;  va_list list;  va_start(list,num);  for(i=0;i<NUM;i++){   x[i]=va_arg(list,&vector3<TT>).x[i];  }  for(j=1;j<num;j++){   for(i=0;i<NUM;i++){    x[i]+=va_arg(list,&vector3<TT>).x[i];   }  }  va_end(list); }

  • コンストラクタの順序?

    以下のソースに関して質問です。 /* library.h */ #pragma comment(lib, "library.lib") class A { public: A(); }; /* library.cpp */ #include "library.h" #include <list> class B { private: std::list<int> m_listi; public: void Func() { m_listi.push_back(0); //フリーズ return; } } g_CB; A::A() { g_CB.Func(); return; } /* test.cpp */ #include "library.h" A CA; int main() { return 0; } library.cppからlibrary.libをつくり、それをtest.cppで使用したところ、 ソースに示したところでプログラムがフリーズしてしまいます。 恐らくクラスBのm_listiが初期化される前にそれを使おうとしたためだと思います。 どうすればそれを避けられるでしょうか。。。

  • 関数でエラー

    #include<stdio.h> int func(int, int); int main() { int a, b, c; a = 10; b = 20; c = func(a, b); printf("%d x %d" = %d\n", a, b, c) return 0; } int func(int a, int b) { int c; c = a * b; return c; } エラーが出てしまうのですが、どうしてエラーが出るのか教えて頂けないでしょうか? エラー一覧です。 ------------------------------------------------------------------------------------------------------------------------------- 配列型 const char[8]を割り当てることはできません。 14行目 ;がreturnの前にありません              16行目 式は変更可能な左辺値である必要があります      14行目 ;が必要です                     16行目 よろしくお願いします。

  • エラーメッセージコード

    古いC言語ソースを解析していたのですが、よく分からないので質問させていただきます。 下記のerror関数は、エラーメッセージを単純にファイル出力するものとして使っており、中身は単純だと思っていました。しかしva_argやcase"s"~"x"など意図が良く分からないものが出てきており、ソースを読むのに熟練してる方に中身が何をしているのか分かり易く解説して頂きたいです。 void error(char *mess,...) { FILE *f2 = stdout; va_list list; int i; int k = 0; char fmt[1000] va_start(list, mess); for(i=0;i < (int)strlen(mess); i++) { if (k >0) { fmt[k++] = mess[i]; fmt[k] = 0; switch (mess[i]) { case's': fprintf(f2,fmt,va_arg(list,char *)); k=0; break; case'c': fprintf(f2,fmt,(char)va_arg(list,int)); k=0; break; case'd': case'x' fprintf(f2,fmt,(char)va_arg(list,int)); k=0; break; } if ( k >= 1000 -2) { fprintf(f2, "too long format string\n"); break; } } else if (mess[i]== '%') { k = 0; fmt[k++] = mess[i]; fmt[k] = 0; } else fprintf(f2, "%c", mess[i]); } va_end(list); exit(1); }

  • グローバル変数について

    ◎1--------------------------------- #include<stdio.h> void func(void); int glb; int main(void) { int a=20; glb=30; printf("main a=%d glb=%d\n",a,glb); func(); return 0; } void func(void) { int b=88; printf("func b=%d glb=%d\n",b,glb); } ------------------------------------- ◎1の実行結果----------------------- main a=20 glb=30 func b=88 glb=30 ------------------------------------- ◎2--------------------------------- #include<stdio.h> void func(void); int glb; int main(void) { int a=20; func(); printf("main a=%d glb=%d\n",a,glb); return 0; } void func(void) { int b=88; int glb=30; printf("func b=%d glb=%d\n",b,glb); } ------------------------------------- ◎2の実行結果----------------------- func b=88 glb=30 main a=20 glb=0 ------------------------------------- 以上2つのプログラムで、◎1は参考書を参考に作成したものです。 ◎1のプログラムで、グローバル変数glbの値をmain( )関数内で設定していたので、次に◎2のようにfunc( )という関数プロトタイプ内で、グローバル変数glbの値を設定し、main( )関数内のprintf文でも表示させようと思ったら、「glb=0」となってしまいました。 なぜこのようになってしまうか、教えてもらえたら嬉しいです。

専門家に質問してみよう