Cコンパイラ(gccとclangを試しました)が関数の引数リストを内部でどのように編成するのか疑問に思いました。この目的のために、たとえば次の2つのファイルで構成されるプログラムを作成しました。
foo.c:
double foo (double (*f) (void *, double), void * arg, double x)
{
return f (arg, x);
}
main.c:
#include <stdio.h>
extern double foo (double (*) (double), double);
double bar (double x)
{
return x + x;
}
int main ()
{
double x = foo (&bar, 2);
printf ("%g\n", x);
return 0;
}
foo
foo.cの引数リストと本体で遊んだ。foo.cがmain.cの定義と一致しない場合、プログラムの動作はC標準に従って未定義である必要があります(私が正しく理解している場合)。
私はいくつかのバリエーション(上記のものを含む)を試しましたが、プログラムは4を出力します。よりエキゾチックなものの1つは
double foo (double x, double (*f) (char, double, int), int r)
{
char a;
return f (a, x, r);
}
。しかし、私が次のようなことを試してみると
double foo (double x, double (*f) (char, double, double), double y)
{
char a;
return f (a, y, x);
}
結果は4にはなりませんが、f(a, x, y)
代わりに書くと、再び4になります。
実験では、引数リストは、さまざまなタイプの引数の順序に関する情報が失われた、さまざまなタイプに対応する配列のリストとして内部的に表されていると思います。たとえば、引数リスト
(char a, double x, int i, double y, char b)
は次のよう(char:{a, b}, int:{i}, double:{x, y})
になり、へのキャストは(double z, char c)
に等しくなります。ここで、型の配列として(char:{c = a}, double:{z = x})
定義しました。T:{}
T
それで:
私の解釈は正しいですか?
この動作はどこかで標準化されていますか?
そのような振る舞いにどれだけ頼ることができますか?
この動作により、いくつかのジェネリックプログラミングが可能になります。誰かが実際にそれを悪用しますか?
ありがとう!