2

そのため、スクリプト言語用のカスタム パーサーを作成しており、省略記号の引数のみを渡せるようにしたいと考えていました。初期変数は必要ありませんが、Microsoft と C は何か他のものを必要としているようです。参考までに、情報については下部を参照してください。

va_* 定義を見てきました

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)      ( ap = (va_list)0 )

私が望まない部分は、va_start の v です。少し背景として、私は goasm に精通しており、スタックがどのように機能するかを知っているので、ここで何が起こっているかを知っています。インラインアセンブリを使用せずに関数スタックベースを取得する方法があるかどうか疑問に思っていました。

私が持っていたアイデア:

#define im_va_start(ap) (__asm { mov [ap], ebp })

などなど...しかし、本当にそれは面倒で、間違っていると感じています。

struct function_table {
    const char* fname;
    (void)(*fptr)(...);
    unsigned char maxArgs;
};
function_table mytable[] = {
{ "MessageBox", &tMessageBoxA, 4 } };

...渡された const char* をソートして mytable 内の一致する関数を見つけ、params を指定して tMessageBoxA を呼び出す関数。また、maxArgs 引数は、有効な数のパラメーターが送信されていることを確認できるようにするためのものです。関数で送信したくない個人的な理由がありますが、それまでの間、私は興味があるからだと言えます。

これは単なる例です。カスタム ライブラリは私が実装するものなので、WinAPI のものを呼び出すだけではありません。

void tMessageBoxA(...) {
// stuff to load args passed
MessageBoxA(arg1, arg2, arg3, arg4);
}

私は __cdecl 呼び出し規則を使用しており、スタックのベース (トップではない) へのポインターを確実に取得する方法を調べましたが、何も見つからないようです。また、関数のセキュリティや型チェックについても心配していません。


編集:ご入力いただきありがとうございます。それは不可能だったようです。

私の修正は終わった

    #define im_va_start(ap) {\
        __asm push eax\
        __asm mov eax, ebp\
        __asm add eax, 8h\
        __asm mov ap, eax\
        __asm pop eax\
    }

そして、私は通常どおり続けることができます。

なぜそれが必要なのかというと、私はいくつかの (ユニークな) read: unsafe トリックを行っており、上で定義した関数へのポインタを持つ構造体配列を使用しています。各関数は一意であり、ほとんどが私のカスタム ライブラリからのものであるため、動作が異なります。うまく説明できませんが、POC が完了したらソースを公開します。

移植性についてはあまり心配していないので、うまくいく必要があります。また、私が行った引数を数えるために:

#define im_va_count(ap, num, t) {\
for(num = 0; *(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) > 0; ++num){ }\
--num;\
im_va_start(argptr);\
}

これは私のために働きます。気になる人がいたら…

4

1 に答える 1

2

残念ながら、これは不可能です。C 標準は次のように述べています。

関数は、さまざまな型のさまざまな数の引数で呼び出すことができます。6.9.1 で説明したように、そのパラメーター リストには 1 つ以上のパラメーターが含まれます。

また、...「1 つ以上のパラメーター」としてカウントされません。さらに遠く、

va_startマクロは、名前のない引数へのアクセスの前に呼び出されます。

それは次のように呼ばれるべきです

va_start(va_list, parmN)

そしてそれ

パラメータparmNは、関数定義の変数パラメータ リストの右端のパラメータの識別子です ( の直前のもの, ...)。

ご覧のとおり、標準 C++ では、省略記号の前に少なくとも 1 つのパラメーターがないと、可変引数関数を使用できません。ポータブルでないアセンブリのトリックは、最も近い方法です。

于 2012-10-27T04:55:35.760 に答える