int max(int n, ...)
私はcdecl呼び出し規約を使用しており、呼び出し先が戻った後に呼び出し元が変数をクリーンアップします。
va_endマクロがどのように機能するのか知りたいのva_startですがva_arg?
呼び出し元は、引数の配列のアドレスをmaxの2番目の引数として渡しますか?
int max(int n, ...)
私はcdecl呼び出し規約を使用しており、呼び出し先が戻った後に呼び出し元が変数をクリーンアップします。
va_endマクロがどのように機能するのか知りたいのva_startですがva_arg?
呼び出し元は、引数の配列のアドレスをmaxの2番目の引数として渡しますか?
C 言語がスタックにパラメーターを格納する方法を見ると、マクロの動作方法が明確になるはずです。
Higher memory address Last parameter
Penultimate parameter
....
Second parameter
Lower memory address First parameter
StackPointer -> Return address
(ハードウェアによっては、スタック ポインターが 1 行下にあり、上位と下位が入れ替わることがあることに注意してください)
引数は、パラメーターの型がなくても、常にこの1のように格納されます。...
va_startマクロは、最初の関数パラメーターへのポインターをセットアップするだけです。
void func (int a, ...)
{
// va_start
char *p = (char *) &a + sizeof a;
}
これはp、2 番目のパラメーターを示しています。マクロはこれva_argを行います:-
void func (int a, ...)
{
// va_start
char *p = (char *) &a + sizeof a;
// va_arg
int i1 = *((int *)p);
p += sizeof (int);
// va_arg
int i2 = *((int *)p);
p += sizeof (int);
// va_arg
long i2 = *((long *)p);
p += sizeof (long);
}
va_endマクロは、p値を に設定するだけNULLです。
ノート:
...この機能がオフになり、コンパイラーがスタックを使用できなくなります。引数がスタックに渡されると、va_「関数」 (ほとんどの場合、マクロとして実装されます) はプライベート スタック ポインターを操作するだけです。va_startこのプライベート スタック ポインタは、 に渡された引数から格納されva_arg、パラメータを反復するときに「スタック」から引数を「ポップ」します。
max次のように、3 つのパラメーターを指定して関数を呼び出すとします。
max(a, b, c);
関数内maxでは、スタックは基本的に次のようになります。
+-----+
| | c |
| | b |
| | | |
| | 戻る |
SP -> +-----+
SPは実際のスタック ポインターであり、実際には ではなく、aスタック上にあるのではなく、それらの値です。関数が終了したときにジャンプする戻りアドレスです。bcret
va_start(ap, n)引数のアドレス (n関数プロトタイプ内) を取得し、そこから次の引数の位置を計算することで、新しいプライベート スタック ポインターを取得します。
+-----+
| | c |
ap -> | b |
| | | |
| | 戻る |
SP -> +-----+
これを使用するva_arg(ap, int)と、プライベート スタック ポインタが指すものを返し、プライベート スタック ポインタを次の引数を指すように変更して「ポップ」します。スタックは次のようになります。
+-----+
ap -> | c |
| | b |
| | | |
| | 戻る |
SP -> +-----+
もちろん、この説明は単純化されていますが、原理を示しています。