2011-01-20 15 views
0

Cの各引数にポインタを得るための一般的な方法は、 のようにvararg関数で行うのですか?Cの関数の引数のポインタを取得するには?

$ 1、$ 2、$ 3

そうでない場合のような特別な構文はそれを定義するいくつかのプリプロセッサマクロはありますか?

C言語では不可能な場合は、Objective Cのソリューションにも興味があります。 私は_cmd特別な隠し パラメータで現在のメソッドのセレクタを取得できることを知っています。どのような種類の_arg1、_arg2はありますか? また、_cmdの後に直接メモリをポイントすることは可能でしょうか? パラメータポインタが隣り合っていると考えると「安全」ですか?自分の質問

TO

UPDATE私はいくつかのアセンブラコードを使用することにより、フレームスタックにアクセスした場合、私はEBPの右側に関数ポインタでホールド を得ることができますか?同じように引数 にアクセスすることは可能ですか?申し訳ありませんが、これは明らかですが、私は多くのアセンブラについて知りません。

+0

ポインタを関数に渡すことについて質問していますか?関数内から引数へのポインタを取得していますか? –

+1

*名前付き*パラメータ、または*実際の*パラメータを "varargs"関数に渡しているのですか? – Pointy

+0

私は存在しないのですか?しかし、なぜそれが必要ですか?あなたはまだ関数にタブポインタを与えることができます(私は質問を理解するためにsurではありません)。 –

答えて

2

現在のスタックフレームポインタと以前のスタックフレームポインタ(つまりbpレジスタ)を抽出し、標準のスタックフレーム構造を使用して、現在のルーチンへの呼び出しで渡されました。どちらの単位がchar、shortまたはlongであるか、それらの2つがlong long/__ int64パラメーターである可能性があるかどうかを判断することはできません。


私はこれについてもう少し考えました。典型的な関数呼び出し "func(a、b)"を考えてみましょう。あなたは(x86-64のために推奨されるいくつかのx86-32コンパイラオプションおよびインテル)レジスタ内のパラメータを持っていない限り、呼び出すコードは、コードが次にあなたがFUNCの処理に来るこの

   ; long *esp,*ebp; 
push b   ; *(--esp)=b; 
push a   ; *(--esp)=a; 
call func  ; *(--esp)=return_address_location; 
return_address_location: 
add esp,8  ; esp+=2; // free memory allocated for passing parameters 

のように判明するでしょう

func: 
push ebp  ; *(--esp)=(long) ebp; // save current ebp <=> current stack frame 
mov ebp,esp ; ebp=esp;    // create new stack frame in ebp 
sub esp,16  ; esp-=4;     // reserve space for local variables <=> sizeof(long)*4 

(func code ...) 

funcに入っていて、パラメータにアクセスする必要があるときは、ebp + 2とebp + 3でアドレス指定します(* ebpには前のebp、ebp + 1に戻りアドレスが入ります)。ローカル変数にアクセスする必要があるときは、ebp-4からebp-1でそれらを扱います(すべてロングではない場合、いくつかのパッキングオプションが設定されていると過度に単純化されるかもしれません)。

中のfuncがその事を行っている、あなたが返す必要があります後:

mov esp,ebp ; esp=ebp;   // unreserve space for local variables 
pop ebp  ; ebp=*(esp++); // restore previous ebp <=> previous stack frame 
ret   ; eip=*(esp++); // pop return address into instruction pointer 

あなたも(パラメータを渡すための)最初のスタック割り当てが右戻った後に解放される方法について説明します最初のスニペットから。

いくつかのヒント:

  • は、コール/リターン シーケンスを シングルステップ( 命令による指示)しながら、自分のために数学を行うと、あなたは、元のを解決する方法 のアイデアを得るでしょう問題。この ので それが
  • がローカルバッファに誤って計算 のmemset/memcpyのを想像して にそれを破壊する方法を知って良いことだすべての のアーキテクチャや実装上 多かれ少なかれ同じに見える基本的なスタックの処理でありますリターンアドレスを含む スタック上のデータ、 前のスタックフレームなど
  • テイクDSの値をメモして、SS (データおよびスタックのセレクタ)と 場合、彼らはあなたの ソリューションのmemcpyを使用することができます正確に同じ値が含まれています〜 コピーあなたが&を使用することができ、DS = ssはFUNC内部 から渡されたパラメータの アドレスを見つけるために、場合それが
  • を助けた場合どんな データ検査のためのメモリや (& PARAM1、& PARAM2)
  • にスタックからのパラメーター
  • (彼ら がマルチスレッド アプリケーションであるかもしれないと)同等のds及びssのかは、あなたは、DSとSSが異なる 状況を処理します「これまで 取り組む」使用 memcpyのバリアントが必要になります場合は
+0

はい私はまだそれをやる方法がわからないけれども、何かについて考えていました。 – CodeFlakes

+0

詳細な回答をいただきありがとうございました!それは間違いなく正しい方向に私を置いた。 – CodeFlakes

2

いいえ、あなたがこれを行うことができる唯一の方法は、stdarg.h

0

いいえ、それを行う特別な方法や特別な表記法はありません。

マクロを定義して各引数を取得し、そのマクロへのポインタを生成することができます(Boostプリプロセッサライブラリを見つける)。私はしたくないと確信しています。

type nth_arg(va_list ap, size_t n) 
{ 
    va_list ap2; 
    va_copy(ap2, ap); 
    while (n--) va_arg(ap2, type); 
    return va_arg(ap2, type); 
} 

は、実際のタイプとtypeを置き換え:可変引数関数の引数はすべて同じタイプ(例えばvoid *)をお持ちの場合

int somefunc(int arg1, char *arg2) 
{ 
    int *p_arg1 = &arg1; 
    char **p_arg2 = &arg2; 
    ... 
} 
0

は、あなたがこのような何かを行うことができます。

関連する問題