pra*_*ash 46 c c++ variadic-functions
我希望用C/C++做到这一点.
我遇到了可变长度参数,但这表明使用libffi的 Python和C解决方案.
现在,如果我想用printf函数包装myprintf
我的工作如下:
void myprintf(char* fmt, ...)
{
va_list args;
va_start(args,fmt);
printf(fmt,args);
va_end(args);
}
int _tmain(int argc, _TCHAR* argv[])
{
int a = 9;
int b = 10;
char v = 'C';
myprintf("This is a number: %d and \nthis is a character: %c and \n another number: %d\n",a, v, b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但结果不如预期!
This is a number: 1244780 and
this is a character: h and
another number: 29953463
Run Code Online (Sandbox Code Playgroud)
我错过的任何一点?
Mar*_*ark 65
问题是你不能将'printf'与va_args一起使用.如果使用可变参数列表,则必须使用vprintf.vprint,vsprintf,vfprintf等(Microsoft的C运行时中还有'安全'版本可以防止缓冲区溢出等)
您的示例工作如下:
void myprintf(char* fmt, ...)
{
va_list args;
va_start(args,fmt);
vprintf(fmt,args);
va_end(args);
}
int _tmain(int argc, _TCHAR* argv[])
{
int a = 9;
int b = 10;
char v = 'C';
myprintf("This is a number: %d and \nthis is a character: %c and \n another number: %d\n",a, v, b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Sha*_*our 11
在C++ 11中,这是一种可能的解决方案Variadic templates:
template<typename... Args>
void myprintf(const char* fmt, Args... args )
{
std::printf( fmt, args... ) ;
}
Run Code Online (Sandbox Code Playgroud)
编辑
正如@rubenvb指出需要考虑的权衡,例如,您将为每个实例生成代码,这将导致代码膨胀.
我也不确定你的意思是纯粹的
在C++中我们使用
#include <cstdarg>
#include <cstdio>
class Foo
{ void Write(const char* pMsg, ...);
};
void Foo::Write( const char* pMsg, ...)
{
char buffer[4096];
std::va_list arg;
va_start(arg, pMsg);
std::vsnprintf(buffer, 4096, pMsg, arg);
va_end(arg);
...
}
Run Code Online (Sandbox Code Playgroud)
实际上,有一种方法可以va_list从包装器调用没有版本的函数。思路是使用汇编器,不接触栈中的参数,临时替换函数返回地址。
Visual C x86 的示例。call addr_printf电话printf():
__declspec( thread ) static void* _tls_ret;
static void __stdcall saveret(void *retaddr) {
_tls_ret = retaddr;
}
static void* __stdcall _getret() {
return _tls_ret;
}
__declspec(naked)
static void __stdcall restret_and_return_int(int retval) {
__asm {
call _getret
mov [esp], eax ; /* replace current retaddr with saved */
mov eax, [esp+4] ; /* retval */
ret 4
}
}
static void __stdcall _dbg_printf_beg(const char *fmt, va_list args) {
printf("calling printf(\"%s\")\n", fmt);
}
static void __stdcall _dbg_printf_end(int ret) {
printf("printf() returned %d\n", ret);
}
__declspec(naked)
int dbg_printf(const char *fmt, ...)
{
static const void *addr_printf = printf;
/* prolog */
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
nop
}
{
va_list args;
va_start(args, fmt);
_dbg_printf_beg(fmt, args);
va_end(args);
}
/* epilog */
__asm {
mov esp, ebp
pop ebp
}
__asm {
call saveret
call addr_printf
push eax
push eax
call _dbg_printf_end
call restret_and_return_int
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
26564 次 |
| 最近记录: |