このコードをコンパイルしようとすると
#include <stdarg.h>
void bar_ptr(int n, va_list *pvl) {
// do va_arg stuff here
}
void bar(int n, va_list vl) {
va_list *pvl = &vl; // error here
bar_ptr(n, pvl);
}
void foo(int n, ...) {
va_list vl;
va_list *pvl = &vl; // fine here
va_start(vl, n);
bar(n, vl);
va_end(vl);
}
int main() {
foo(3, 1, 2, 3);
return 0;
}
GCCコンパイラinitialization from incompatible pointer type
は、bar
関数に関する警告を出力します。同一のステートメントはで問題ありませんfoo
。
typeの引数の型va_list
がでないようva_list
です。これは次のような静的アサーションで簡単にテストできます
_Static_assert(sizeof(vl) == sizeof(va_list), "invalid type");
でbar
機能。GCCでは、_Static_assert
失敗します。同じことはしてC ++にもテストすることができるdeclytpe
とstd::is_same
。
このスレッドで説明されているように考えるために、のva_list vl
引数のアドレスを取り、bar
それをの引数として渡しbar_ptr
たいと思います。一方、bar_ptr(n, pvl)
から直接呼び出してmain
、を置き換えても問題ありませんbar(n, vl)
。
C11最終草案の脚注253によると、
へのポインタを作成し、
va_list
そのポインタを別の関数に渡すことが許可されています
va_list
関数本体ではなく、関数の引数として定義されている場合、これを実行できないのはなぜですか?
回避策:
これで問題が解決しない場合でも、回避策としてはbar
、va_copyで作成した引数のローカルコピーを使用しての内容を変更します。
void bar(int n, va_list vl) {
va_list vl_copy;
va_copy(vl_copy, vl);
va_list *pvl = &vl_copy; // now fine here
bar_ptr(n, pvl);
va_end(va_copy);
}
va_list
あなたは、実際に渡しています、va_list
。
va_list
ます。3番目の関数があるとします。その関数へのvoid bar_ptr(va_list *pvl);
ポインターを渡しva_list vl
ます。質問を編集して指定します。
va_copy
あなたが持っているアプローチは、この問題に対する標準的な解決策です。基本的にこれを結論付ける過去の質問がいくつかあります。
va_list
。