14

printfのような可変個引数関数は、取得した引数の数をどのように見つけることができますか?

引数の量は明らかに(非表示の)パラメーターとして渡されません(ここのasmの例でprintfの呼び出しを参照してください)。

トリックは何ですか?

4

4 に答える 4

14

秘訣は、なんとかして彼らに話すことです。printf型情報も含むフォーマット文字列を指定する必要があります(ただし、正しくない可能性があります)。この情報を提供する方法は、主にユーザー契約であり、多くの場合エラーが発生しやすくなります。

呼び出し規約について:通常、引数は左から右にスタックにプッシュされ、最後にバックジャンプアドレスにプッシュされます。呼び出し元のルーチンはスタックをクリアします。したがって、呼び出されたルーチンがパラメータの数を知る必要はありません。

編集:C ++ 0xには、可変個引数関数を呼び出すための安全な方法(typesafeでも!)があります!

于 2011-03-11T12:14:13.787 に答える
9

暗黙的に、フォーマット文字列から。stdarg.hには、渡された引数の「可変」数の合計を取得するためのマクロが含まれていないことに注意してください。これは、コードサイズが大きくなっても、C呼び出し規約で呼び出し元がスタックをクリーンアップする必要がある理由の1つでもあります。

于 2011-03-11T12:32:50.423 に答える
9

これが、C呼び出し規約で引数が逆の順序でプッシュされる理由です。例:

電話をかける場合:

printf("%s %s", foo, bar);

スタックは次のようになります。

  ...
+-------------------+
| bar               |
+-------------------+
| foo               |
+-------------------+
| "%s %s"           |
+-------------------+
| return address    |
+-------------------+
| old frame pointer | <- frame pointer
+-------------------+
  ...

引数は、フレームポインターからのオフセットを使用して間接的にアクセスされます(フレームポインターは、スタックポインターから計算する方法を知っているスマートコンパイラーによって省略できます)。このスキームでは、最初の引数は常に既知のアドレスにあり、関数は最初の引数が指示する数の引数にアクセスします。

次のことを試してください。

printf("%x %x %x %x %x %x\n");

これにより、スタックの一部がダンプされます。

于 2011-03-14T00:29:14.980 に答える
5
  • AMD64 System V ABI( Linux、Mac OS X)はal、標準のIA-32呼び出し規約とは異なり、(RAXの下位バイト)で数値ベクトル(SSE / AVX)変数を渡します。参照:printfを呼び出す前に%eaxがゼロになるのはなぜですか?

    ただし、最大8個(使用するレジスタの最大数)のみです。また、IIRC、ABIでは、XMM / YMM / ZMM引数の実際の数より大きくalすることができますが、小さくすることはできません。したがって、一般的に、FP引数の数を常に示しているわけではありません。8を超える数はわかりませんが、過大評価することは許可されています。al

    「3.5.7変数引数リスト」に記載されている「レジスタ保存領域」への不要なベクトルレジスタの保存をスキップすることは、パフォーマンス上の理由でのみ使用できます。たとえば、GCCはal!=0、XMM0..7をテストしてから、スタックにダンプするか、何もダンプしないコードを作成します。(または、関数がどこでも使用VA_ARGする場合は__m256、YMM0..7。)

  • 経営幹部レベルでは、他の人が述べているようにフォーマット文字列を解析する以外にも他の手法があります。また、次のこともできます。

    • execl(void *)0のように、最後の引数を示すために番兵を渡します。

      関数属性を使用して、sentinelGCCがコンパイル時にそれを強制できるようにする必要があります。C警告関数呼び出しにセンチネルがありません

    • varargsの数を含む追加の整数引数として渡します

    • function属性を使用して、formatGCCがprintfまたはなどの既知のタイプのフォーマット文字列を適用できるようにします。strftime

関連:可変引数はgccでどのように実装されていますか?

于 2015-07-20T15:11:40.093 に答える