だから私は2つの関数があり、どちらも同じような引数を持っています
void example(int a, int b, ...);
void exampleB(int b, ...);
ここでをexample
呼び出しますがexampleB
、変更せずに変数引数リストの変数を渡すにはどうすればよいですかexampleB
(これはすでに他の場所でも使用されているため)。
だから私は2つの関数があり、どちらも同じような引数を持っています
void example(int a, int b, ...);
void exampleB(int b, ...);
ここでをexample
呼び出しますがexampleB
、変更せずに変数引数リストの変数を渡すにはどうすればよいですかexampleB
(これはすでに他の場所でも使用されているため)。
回答:
直接行うことはできません。あなたは取る関数を作成する必要がありますva_list
:
#include <stdarg.h>
static void exampleV(int b, va_list args);
void exampleA(int a, int b, ...) // Renamed for consistency
{
va_list args;
do_something(a); // Use argument a somehow
va_start(args, b);
exampleV(b, args);
va_end(args);
}
void exampleB(int b, ...)
{
va_list args;
va_start(args, b);
exampleV(b, args);
va_end(args);
}
static void exampleV(int b, va_list args)
{
...whatever you planned to have exampleB do...
...except it calls neither va_start nor va_end...
}
, ...
は、シグネチャで可変引数リストをとる関数に名前付きの最初の引数が必要です。変数の引数をに変換した場合、のみを受け取る別の関数にをva_list
渡すことができますが、その関数(または関数が呼び出す関数)には、の内容を知るための何らかの方法が必要です。va_list
va_list
va_list
たぶんここの池に岩を投げ入れますが、C ++ 11可変テンプレートでうまく動作するようです:
#include <stdio.h>
template<typename... Args> void test(const char * f, Args... args) {
printf(f, args...);
}
int main()
{
int a = 2;
test("%s\n", "test");
test("%s %d %d %p\n", "second test", 2, a, &a);
}
少なくとも、で動作しg++
ます。
args...
また、printfをラップしたかったので、ここで役立つ回答を見つけました。
私はパフォーマンスにまったく興味がありませんでした(このコードはいくつかの方法で改善できると確信しています。そうすることをお気軽にしてください:))、これは一般的なデバッグ印刷専用であるため、これを行いました:
//Helper function
std::string osprintf(const char *fmt, ...)
{
va_list args;
char buf[1000];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args );
va_end(args);
return buf;
}
これはこのように使用できます
Point2d p;
cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y);
instead of for example:
cout << "Point2d: ( " << setw(3) << p.x << ", " << p.y << " )";
c ++ ostreamはいくつかの点で美しいですが、括弧、コロン、コンマなどの小さな文字列を数値の間に挿入してこのようなものを印刷したい場合、実際には恐ろしくなります。
ちなみに、多くのC実装には内部v?printfバリエーションがあり、IMHOはC標準の一部であるはずでした。正確な詳細は異なりますが、一般的な実装では、文字出力関数ポインタと、何が起こるかを示す情報を含む構造体を受け入れます。これにより、printf、sprintf、およびfprintfはすべて同じ「コア」メカニズムを使用できます。たとえば、vsprintfは次のようになります。
void s_out(PRINTF_INFO * p_inf、char ch) { (*(p_inf-> destptr)++)= ch; p_inf-> result ++; } int vsprintf(char * dest、const char * fmt、va_list args) { PRINTF_INFO p_inf; p_inf.destptr = dest; p_inf.result = 0; p_inf.func = s_out; core_printf(&p_inf、fmt、args); }
次に、core_printf関数は、出力される文字ごとにp_inf-> funcを呼び出します。出力関数は、文字をコンソール、ファイル、文字列、またはその他のものに送信できます。実装がcore_printf関数(およびそれが使用するセットアップメカニズム)を公開する場合、あらゆる種類のバリエーションで拡張できます。
あなたがラップしているというコメントとvsprintf
これがC ++としてタグ付けされているというコメントに基づいて、これを実行しようとせずに、代わりにC ++ iostreamを使用するようにインターフェイスを変更することをお勧めします。これらにはprint
、タイプセーフやprintf
処理できないアイテムを印刷できるなど、一連の機能に勝る利点があります。現在、一部のやり直しにより、将来の苦痛を大幅に軽減することができます。
これが唯一の方法であり、それを行うための最良の方法でもあります。
static BOOL(__cdecl *OriginalVarArgsFunction)(BYTE variable1, char* format, ...)(0x12345678); //TODO: change address lolz
BOOL __cdecl HookedVarArgsFunction(BYTE variable1, char* format, ...)
{
BOOL res;
va_list vl;
va_start(vl, format);
// Get variable arguments count from disasm. -2 because of existing 'format', 'variable1'
uint32_t argCount = *((uint8_t*)_ReturnAddress() + 2) / sizeof(void*) - 2;
printf("arg count = %d\n", argCount);
// ((int( __cdecl* )(const char*, ...))&oldCode)(fmt, ...);
__asm
{
mov eax, argCount
test eax, eax
je noLoop
mov edx, vl
loop1 :
push dword ptr[edx + eax * 4 - 4]
sub eax, 1
jnz loop1
noLoop :
push format
push variable1
//lea eax, [oldCode] // oldCode - original function pointer
mov eax, OriginalVarArgsFunction
call eax
mov res, eax
mov eax, argCount
lea eax, [eax * 4 + 8] //+8 because 2 parameters (format and variable1)
add esp, eax
}
return res;
}