struct.h :
struct S { int * a; int * b; };
ac :
#include <stdio.h> #include "struct.h" struct S f(struct S v) { printf( "va =%d、vb =%d \ n"、* va、* vb); return v; }
bc :
#include <stdio.h> #include "struct.h" int main() { int a = 1、b = 2; struct S v = {&a、&b}; f(v); printf( "a =%d、b =%d \ n"、a、b); 0を返します。 }
メイクファイル :
すべて:テスト ./test テスト:ac bc struct.h gcc ac bc -g -oテスト
質問 :実行時に何が印刷されますか? 少なくとも1分考えてください。 デバッガーを使用して、この簡単なプログラムを実行してください。
回答 :事前に知られていませんが、すべてfの呼び出し時点でプロトタイプが利用できないためです。 同時に、渡されたパラメーターは、呼び出された関数が期待するものに正確に対応します 。
たとえば、私のシステムでは、出力は次のようになります。
va = 2、vb = 0 a = 8559808、b = -2398008
もちろん、呼び出しの時点でプロトタイプが存在しないことは肉眼で見ることができますが、この場合、通常無害な「関数の暗黙の宣言」がそのような悲惨な結果をもたらすのはなぜですか?
gccが従うABIに感謝します。
ABIは、言語標準が「実装固有」と呼ぶもの、または当然のことと見なされるものの多くの側面を定義しています。 特に、i386 ABIは、関数が呼び出されたときにマシンスタックのタイプを判別します。 構造体/共用体を返す関数の場合、次のことが規定されています。
呼び出し後位置を返した後 4n + 4(%esp)| 単語n | | 単語n | 4n-4(%esp) | ... | | ... | 8(%esp)| ワード1 | | ワード1 | 0(%esp) | ------------ | | -------------- | 4(%esp)| 住所| | 定義されていません| | 結果| | | | ------------ | | | 0(%esp)| 住所| | | | 戻る| | | | ------------ | | -------------- |
ご覧のとおり、通常の呼び出しと比較して、もう1つのパラメーターが追加されます。このパラメーターは、呼び出される関数がスタックから取り出します。戻り値が書き込まれるアドレスです。
検討中のケースで何が起こるか(呼び出し側の関数がスタックに置かれ、呼び出された関数がそれについてどう思うか、そして戻った後のスタックにそれが描かれている):
すぐに呼び出される 戻り後の関数 (予想) 16(%esp)| ローカル| | | | ローカル| | | | ------------ | | | 12(%esp)| 変数| | vb | | 変数| | ============== | | | | -------------- | 8(%esp)| vb | | va | | vb | 0(%esp) | ------------ | | ------------ | | =============== | 4(%esp)| va | | 住所| | 定義されていません| | | | 結果| | | | ============== | | ------------ | | | 0(%esp)| 住所| | 住所| | | | 戻る| | 戻る| | | | ------------ | | ------------ | | -------------- |
次の異常が明らかです。
- 呼び出された関数は、1のシフト(va“ inside” = vb“ outside”)を持つパラメーターを見ます。
- 呼び出された関数は、戻り値で、最初の引数の値に等しいアドレスのメモリを上書きします(vaのガベージ)。
- 戻った後、スタックポインタは1ワード戻ります。 コンパイラーが変更せずにスタックにプッシュするパラメーターを見つけるために、変更せずにそれを見つけることを期待していると考えると、espからのオフセットでローカル変数にアクセスし、esp 8に追加してクリーンアップを実行しようとすることは非常に悪いです
ここに物語があります。
結論の代わりに :
コンパイラの警告は、通常考えられるよりも重要な場合があります。
プラットフォームのABIを知ることで、作業が楽になる場合があります。
しかし、x86_64ではそのような効果はありません。
良い一日を