‹テンプレート マニュアルは統合が検討されています。›
stdarg.hは、 Cプログラミング言語のC標準ライブラリのヘッダーであり、関数が不定数の引数を受け入れることを可能にします。[1]数と型が不明な関数引数のリストをステップ実行する機能を提供します。C ++は、この機能をヘッダーで提供します。
cstdarg
の内容は通常、可変個引数関数stdarg.hで使用されますが、可変個引数関数によって呼び出される他の関数 (たとえば、) でも使用されることがあります。
vprintf
可変長関数の作成
可変個引数関数は、可変個の引数を取る関数であり、最後のパラメータの代わりに省略記号printfを使用して宣言されます。このような関数の例は です。宣言と定義はそれぞれ次のように同じように行われます。
intチェック( int a 、double b 、...);
intチェック( int a 、double b 、...){ //... }
標準によれば、名前付きパラメータを持たない可変長関数はC17以前では許可されていませんが、C++およびC23 [2]ではそのような宣言が許可されています。
C では、名前付きパラメータを指定する場合、省略記号の前にコンマを付ける必要がありますが、C++ ではオプションです。
K&R Cスタイルの関数宣言では省略記号を使用しないものもあります。 [3]
stdarg.h 型
stdarg.h マクロ
引数へのアクセス
標準によれば、名前のない引数にアクセスするには、va_list可変長関数の 型の変数を介してアクセスでき、マクロva_startも関数の最後の名前付きパラメータとして提供されます。C23 では、2 番目の引数はオプションであり、評価されません。[2]
この後、マクロを呼び出すたびにva_arg次の引数が生成されます。 の最初の引数はva_argでva_list、2 番目の引数は関数に渡される次の引数の型です。最後のステップとして、関数が戻る前にva_endでマクロを呼び出す必要がありますva_list。すべての引数を読み込む必要はないことに注意してください。
C99 ではva_copy、 の状態を複製できる追加のマクロ が提供されていますva_list。マクロ呼び出しにより が にva_copy(va2, va1)コピーされます。
va1va2
可変長関数に渡される名前のない引数を数えたり分類したりするための定義された方法はありません。関数は何らかの方法でこれを決定する必要がありますが、その方法はさまざまです。一般的な規則は次のとおりです。
名前のない引数を他の呼び出しに渡す
名前なし引数リストのサイズは一般に不明であるため、ほとんどのコンパイラで採用されている呼び出し規約va_listでは、受け取り関数内で が指す名前なし引数ブロックのサイズを判別できません。その結果、名前なし引数を別の可変長関数に転送する信頼性の高い汎用的な方法もありません。引数リストのサイズを間接的な方法 (たとえば、 の書式文字列を解析するfprintf()) で判別できる場合でも、動的に判別された引数の数を内部の可変長呼び出しに渡す移植可能な方法はありません。これは、このような呼び出しに渡される引数の数とサイズが一般にコンパイル時にわかっている必要があるためです。この制限は、可変長関数の代わりに可変長マクロを使用することで、ある程度緩和できます。さらに、ほとんどの標準ライブラリ プロシージャでは、名前なし引数リスト自体ではなく、名前なし引数リスト (つまり、初期化された変数) への参照vを受け入れる、プレフィックス付きの代替バージョンが提供されています。たとえば、 は、実際の名前なし引数リストではなくを期待するの代替バージョンです。したがって、ユーザー定義の可変長引数関数は、 を使用して変数を初期化し、それを適切な標準ライブラリ関数に渡すことができます。これにより、名前のない引数リストを値渡しではなく参照渡しで渡すことになります。C では名前のない引数リストを値渡しで確実に渡す方法がないため、代わりに を受け入れる同等の関数を提供せずに可変長引数API関数を提供することは、不適切なプログラミング手法と見なされます。
va_listvfprintf()fprintf()va_listva_listva_startva_list
型安全性
一部の C 実装では、書式文字列とセンチネルの適切な使用をコンパイラがチェックできる C 拡張機能が提供されています。これらの拡張機能がなければ、コンパイラは通常、渡された名前のない引数が関数が期待する型であるかどうかをチェックしたり、必要な型に変換したりすることはできません。したがって、型が一致しない場合は未定義の動作がint *発生するため、この点については正確性を保証するように注意する必要があります。たとえば、期待される型が の場合、 として null ポインターを渡す必要があります(int *)NULL。 とだけ記述すると、NULL型が または のいずれかの引数になりますintが、どちらも正しくありません。もう 1 つの考慮事項は、名前のない引数に適用されるvoid *デフォルトの引数の昇格floatです。 A は自動的に に昇格されますdouble。同様に、 よりも狭い型の引数はまたはintに昇格されます。名前のない引数を受け取る関数は、昇格された型を期待する必要があります。[引用が必要]intunsigned int
GCC には渡された引数をチェックする拡張機能があります。
format(archetype, string-index, first-to-check)
format 属性は、関数がprintf、scanf、strftimeまたはstrfmonスタイルの引数を取り、それらがフォーマット文字列に対して型チェックされる必要があることを指定します。たとえば、次の宣言:
extern int my_printf ( void * my_object 、const char * my_format 、...) __attribute__ (( format ( printf 、2 、3 )));
コンパイラは、呼び出し時の引数がスタイル書式文字列引数[4]my_printfと一致するかどうかをチェックする。printfmy_format
例
#include <stdio.h> #include <stdarg.h>
/*変数の合計を取得*/
void sum ( int count , ...) { va_list ap ; int i = 0 ; int sum = 0 ; va_start ( ap , arg1 ); for ( i = 0 ; i < count ; i ++ ) sum += va_arg ( ap , int ); va_end ( ap ); return sum ; }
int main ( void ) { printf ( "%i" , sum ( 2 , 1 , 3 )); 0を返す; }
このプログラムの出力は次のようになります。
4
可変引数.h
POSIXの古いバージョンでは、レガシー ヘッダー が定義されています。varargs.hこれは C の標準化以前にさかのぼり、 と同様の機能を提供します。このヘッダーは、ISO C にも POSIX にも属していません。Single UNIX 仕様stdarg.hの第 2 バージョンで定義されているファイルには、次の例外を除き、 C89 のすべての機能が含まれています。
stdarg.h
- 標準Cの新しいスタイルの定義では使用できません
- 与えられた引数は省略できます(標準Cでは少なくとも1つの引数が必要です)
インターフェースも異なります。たとえばprintargs、次のように記述します。
#include <stdio.h> #include <varargs.h>
/* "void" 型はありません。暗黙の int 戻り値を使用してください。 */
printargs ( arg1 , va_alist ) va_dcl /* ここではセミコロンは不要です。 */ { va_list ap ; int i ;
va_start ( ap ); /* va_list のみが与えられます! */ for ( i = arg1 ; i >= 0 ; i = va_arg ( ap , int )) printf ( "%d " , i ); va_end ( ap ); putchar ( '\n' ); return ; }
同じように呼ばれます。
varargs.hは、実装の仕組み上、古いスタイルの関数定義を必要とします。[5]逆に、古いスタイルの関数定義とを混在させることはできませんstdarg.h。
参考文献
- ^ 「IEEE Std 1003.1 stdarg.h」。2009年7月4日閲覧。
- ^ ab Gilding, Alex; Meneide, JeanHeyd (2022-04-15). 「WG14-N2975: 可変長パラメータリストの要件の緩和、v3」(PDF)。
- ^ 「旧式の関数定義」. GNU C言語. 2007年. 2024年11月15日閲覧。
- ^ 「5.27 C言語ファミリへの拡張 - 関数の属性の宣言」。2009年1月3日閲覧。
- ^ 「Single UNIX 仕様 varargs.h」 。2007年 8 月 1 日閲覧。
