__stdcall 関数に省略記号を使用できないことはわかっていますが、__cdecl または __stdcall 以外の規則を呼び出すための stdarg.h 関数をサポートするプラットフォームがないことを確認したいと思います。
5 に答える
呼び出し規則は、呼び出し元がスタックから引数をクリアするものでなければなりません (呼び出し先は何が渡されるかわからないため)。
ただし、これは Microsoft が「__cdecl」と呼んでいるものとは必ずしも一致しません。たとえば、SPARC では、通常、引数をレジスタに渡します。これは、SPARC がそのように動作するように設計されているためです。そのレジスタは基本的に、コールが十分に深くなると、メイン メモリにスピルされるコール スタックとして機能します。それらはもはやレジスターに収まりません。
私はそれについて確信が持てませんが、IA64 (Itanium) でもほぼ同じであると予想します。また、巨大なレジスタ セット (メモリが機能する場合は数百) も備えています。私が間違っていなければ、レジスタの使用方法についてはもう少し寛容ですが、少なくとも多くの場合、同様に使用されることを期待しています。
なぜこれがあなたにとって重要なのですか?stdarg.h とそのマクロを使用するポイントは、呼び出し規則の違いをコードから隠して、可変引数を移植可能に操作できるようにすることです。
コメントに基づいて編集:さて、あなたがしていることを理解しました(少なくとも答えを改善するのに十分です)。既定の ABI のバリエーションを処理するコードが既に (明らかに) ある場合、作業はより簡単になります。それは、可変引数関数が常に「デフォルトの ABI」を使用するかどうかという問題だけを残しています。「stdcall」と「default」が唯一のオプションであるため、その答えはイエスだと思います。たとえば、Windows では経験則を破り、stdcall の代わりに cdecl 呼び出し規約を使用しますwsprintf
。wprintf
これを判断できる最も確実な方法は、呼び出し規約を分析することです。可変個引数関数が機能するには、呼び出し規約にいくつかの属性が必要です。
- 呼び出し先は、可変引数リストの一部ではないパラメーターに、スタックの先頭からの固定オフセットからアクセスできる必要があります。これには、コンパイラがパラメーターをスタックに右から左にプッシュする必要があります。(これには、 への最初のパラメーター
printf
、フォーマット仕様などが含まれます。また、可変引数リスト自体のアドレスも、既知の場所から派生する必要があります。) - 関数が返されたら、呼び出し元はスタックからパラメーターを削除する必要があります。これは、呼び出し元のコードを生成している間、最初にスタックにプッシュされたパラメーターの数を知っているのはコンパイラだけだからです。可変個引数関数自体には、この情報はありません。
stdcall
呼び出し先がスタックからパラメーターをポップする責任があるため、機能しません。古い 16 ビット Windows の時代には、pascal
パラメーターがスタックに左から右にプッシュされたため、機能しませんでした。
もちろん、他の回答が示唆しているように、多くのプラットフォームでは呼び出し規約に関して選択肢がなく、この質問はそれらのプラットフォームには関係ありません。
AFAIK、呼び出し規約の多様性は、x86上のDOS/Windowsに固有のものです。他のほとんどのプラットフォームでは、コンパイラにOSが付属しており、規則が標準化されています。