このコードをコンパイルしようとすると
#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。