変数パラメーター リストを受け取る関数のサブセットを処理する関数への関数ポインターを作成したいと考えています。ユースケースは、パラメーターの特定のリストを受け取る関数に取る関数をキャストする...
ため、友人を扱わずに変数パラメーターを処理できますva_list
。
次のコード例では、変数パラメーターを持つ関数を、ハードコードされたパラメーター リストを持つ関数にキャストしています (逆も同様です)。これは機能します (またはたまたま機能します) が、使用中の呼び出し規約による偶然かどうかはわかりません。(2 つの異なる x86_64 ベースのプラットフォームで試しました。)
#include <stdio.h>
#include <stdarg.h>
void function1(char* s, ...)
{
va_list ap;
int tmp;
va_start(ap, s);
tmp = va_arg(ap, int);
printf(s, tmp);
va_end(ap);
}
void function2(char* s, int d)
{
printf(s, d);
}
typedef void (*functionX_t)(char*, int);
typedef void (*functionY_t)(char*, ...);
int main(int argc, char* argv[])
{
int x = 42;
/* swap! */
functionX_t functionX = (functionX_t) function1;
functionY_t functionY = (functionY_t) function2;
function1("%d\n", x);
function2("%d\n", x);
functionX("%d\n", x);
functionY("%d\n", x);
return 0;
}
これは未定義の動作ですか?はいの場合、これが機能しないプラットフォームの例、またはより複雑なユースケースを考えると失敗するように私の例を微調整する方法を誰かに教えてもらえますか?
編集:このコードがより複雑な引数で壊れるという意味に対処するために、私は私の例を拡張しました:
#include <stdio.h>
#include <stdarg.h>
struct crazy
{
float f;
double lf;
int d;
unsigned int ua[2];
char* s;
};
void function1(char* s, ...)
{
va_list ap;
struct crazy c;
va_start(ap, s);
c = va_arg(ap, struct crazy);
printf(s, c.s, c.f, c.lf, c.d, c.ua[0], c.ua[1]);
va_end(ap);
}
void function2(char* s, struct crazy c)
{
printf(s, c.s, c.f, c.lf, c.d, c.ua[0], c.ua[1]);
}
typedef void (*functionX_t)(char*, struct crazy);
typedef void (*functionY_t)(char*, ...);
int main(int argc, char* argv[])
{
struct crazy c =
{
.f = 3.14,
.lf = 3.1415,
.d = -42,
.ua = { 0, 42 },
.s = "this is crazy"
};
/* swap! */
functionX_t functionX = (functionX_t) function1;
functionY_t functionY = (functionY_t) function2;
function1("%s %f %lf %d %u %u\n", c);
function2("%s %f %lf %d %u %u\n", c);
functionX("%s %f %lf %d %u %u\n", c);
functionY("%s %f %lf %d %u %u\n", c);
return 0;
}
それはまだ動作します。これがいつ失敗するかの具体的な例を誰か指摘できますか?
$ gcc -Wall -g -o varargs -O9 varargs.c
$ ./varargs
this is crazy 3.140000 3.141500 -42 0 42
this is crazy 3.140000 3.141500 -42 0 42
this is crazy 3.140000 3.141500 -42 0 42
this is crazy 3.140000 3.141500 -42 0 42