『OOC』ノート(3)——C言語が長くなるパラメータva_listの使い方
4803 ワード
『OOC』ノート(3)——C言語が長くなるパラメータva_listの使い方
C言語で有名なprintf関数は,許容できるパラメータ数が固定されていない,これが長くなるパラメータである.C#にはparamsというキーワードもあり、長くなるパラメータを実現します.
Cで1つの長くなるパラメータの関数を受け入れることができることを実現します
例として次のようになります.
変長パラメータを使用する関数を記述するには、次の手順に従います.
まずstdargを参照する.h.
次に、関数宣言で「...」を使用します.この関数が長くなるパラメータを使用できることを示します.
注意する前には少なくとも普通のパラメータが必要です.(標準Cではないかもしれませんが、保守的なほうがいいです)
では、これらの数、タイプが不確定なパラメータをどのように使用しますか?
va_Listタイプのlist変数は「...」を巡回できます.に表示されます.
vaでstart()を使用してlist変数を初期化します.va_start()は「...」に隣接する必要がありますの左にあるパラメータ名です.(例のx)
va_arg()は、次のパラメータ値を取得するために使用されます.このパラメータ値のタイプは、符号化時に決定する必要があります.
va_end()はlistのループを終了するために使用されます.その後vaを再利用できますstart()、va_arg()、va_end()は、各可変パラメータ値を順次取得する.
注意事項
addのこの例では、可変パラメータの処理が完了したことを知るには、最後のパラメータは0でなければなりません.他に方法はない.つまり、外力を借りずに伝わる可変パラメータがいくつあるかを知ることはできません.
printf("%d,%s,%c",1,"11",'1');関数ではprintfがフォーマットパラメータ「%d,%s,%c」を解析し、3つのフォーマット出力記号が表示されるので、3つの可変パラメータが入力されたと考えられます.もしあなたが多く伝わったり少なくなったりしたら、プログラムが間違っている可能性があります.コンパイラはこのエラーを検出できません.
list変数はパラメータとして他の関数に渡すことができます.(例えばvprintf(「xxx」,list);)
可変パラメータを渡すとintまたはlongとして整数が渡され、float型はdoubleとして渡されます.
va_arg()の2番目のパラメータ(例のint)は、あまり複雑ではないはずです.(この話はあいまいだ)
要するに,C言語における変長パラメータの使用は良いプログラミング実践ではない.なるべく避けられる.
原理は何ですか.
va_リストはstdioです.hで定義されたタイプ.va_start、va_arg、va_endは3つのマクロ定義です.
va_startはlistに((vのアドレス)+(vの長さ))を付与する.関数呼び出し時のパラメータのメモリレイアウトに基づいてlistは最初の可変パラメータを指します.(例2)
毎回va_を呼び出すargは、現在のパラメータ値を取得し、apポインタを次のパラメータに指します.
呼び出しva_endはapを0にリセットします.
したがって、この可変パラメータの原理は、関数スタックのパラメータ上を移動して可変パラメータを順次取得する反復器である.
C言語で有名なprintf関数は,許容できるパラメータ数が固定されていない,これが長くなるパラメータである.C#にはparamsというキーワードもあり、長くなるパラメータを実現します.
1 printf("Hello Mozart!");
2 printf("Hello %s!", "Mozart");
3 printf("%d: Hello %s!", 77, "Mozart");
Cで1つの長くなるパラメータの関数を受け入れることができることを実現します
例として次のようになります.
1 #include <stdarg.h>
2
3 int add(const char * testString, int x, ...)
4 {
5 printf("%s
", testString);
6 va_list list;
7 va_start(list, x);
8 int result = 0;
9
10 for(;;)
11 {
12 int p = va_arg(list, int);
13 if(p == 0)
14 break;
15 result += p;
16 }
17 va_end(list); // cleanup , set 'lsit' to NULL
18 return result;
19 }
20
21 /* error: ISO C requires a named argument before '...'
22 void add2(...)
23 {
24 }
25 */
26
27 int main()
28 {
29 int result = add("test case 1: ", 1, 2, 3, 4, 5, 0);
30 printf("%d
", result);
31 system("PAUSE");
32 return 0;
33 }
34
35 /*
36 This program print as follows:
37 test case 1:
38 15
39 */
変長パラメータを使用する関数を記述するには、次の手順に従います.
まずstdargを参照する.h.
次に、関数宣言で「...」を使用します.この関数が長くなるパラメータを使用できることを示します.
注意する前には少なくとも普通のパラメータが必要です.(標準Cではないかもしれませんが、保守的なほうがいいです)
では、これらの数、タイプが不確定なパラメータをどのように使用しますか?
va_Listタイプのlist変数は「...」を巡回できます.に表示されます.
vaでstart()を使用してlist変数を初期化します.va_start()は「...」に隣接する必要がありますの左にあるパラメータ名です.(例のx)
va_arg()は、次のパラメータ値を取得するために使用されます.このパラメータ値のタイプは、符号化時に決定する必要があります.
va_end()はlistのループを終了するために使用されます.その後vaを再利用できますstart()、va_arg()、va_end()は、各可変パラメータ値を順次取得する.
注意事項
addのこの例では、可変パラメータの処理が完了したことを知るには、最後のパラメータは0でなければなりません.他に方法はない.つまり、外力を借りずに伝わる可変パラメータがいくつあるかを知ることはできません.
printf("%d,%s,%c",1,"11",'1');関数ではprintfがフォーマットパラメータ「%d,%s,%c」を解析し、3つのフォーマット出力記号が表示されるので、3つの可変パラメータが入力されたと考えられます.もしあなたが多く伝わったり少なくなったりしたら、プログラムが間違っている可能性があります.コンパイラはこのエラーを検出できません.
list変数はパラメータとして他の関数に渡すことができます.(例えばvprintf(「xxx」,list);)
可変パラメータを渡すとintまたはlongとして整数が渡され、float型はdoubleとして渡されます.
va_arg()の2番目のパラメータ(例のint)は、あまり複雑ではないはずです.(この話はあいまいだ)
要するに,C言語における変長パラメータの使用は良いプログラミング実践ではない.なるべく避けられる.
原理は何ですか.
typedef char* va_list
#define va_start(ap,v)(ap=(va_list)&v+_INTSIZEOF(v))
#define va_arg(ap,t)(*(t*)((ap +=_INTSIZEOF(t))-_INTSIZEOF(t)))
#define va_end(ap) ( ap = (va_list)0)
va_リストはstdioです.hで定義されたタイプ.va_start、va_arg、va_endは3つのマクロ定義です.
va_startはlistに((vのアドレス)+(vの長さ))を付与する.関数呼び出し時のパラメータのメモリレイアウトに基づいてlistは最初の可変パラメータを指します.(例2)
毎回va_を呼び出すargは、現在のパラメータ値を取得し、apポインタを次のパラメータに指します.
呼び出しva_endはapを0にリセットします.
したがって、この可変パラメータの原理は、関数スタックのパラメータ上を移動して可変パラメータを順次取得する反復器である.