要求mysprintf的参数列表必须与sprintf一致,即int mysprintf(char *, const char *, ...)
也就是原有代码中对sprintf的调用可直接用mysprintf进行替换
必须强调一点(请大家注意审题):不是自己写一个函数来sprintf的功能,而是对其封装,即
int mysprintf(char *, const char *, ...)
{
// do something
sprintf(,,...); // 关键就是这里,如何解析mysprintf的传入参数并传给sprintf,这包括个数、类型等待
// do something
return len;
}
小弟在此谢谢了!
24 个解决方案
#1
应该用 vsprintf
#2
感谢#1朋友,谢谢!
事实上,我在描述问题时进行了类比简化。我的实际问题跟sprintf相似,于是我就用它做了类比。我的实际问题是,第三方提供的DLL的接口函数的参数中含有省略号,而我要对其封装调用。这个DLL属于工控方面的,函数实现向PCI总线发送一些指令,所以显然没法用vsprintf
事实上,我在描述问题时进行了类比简化。我的实际问题跟sprintf相似,于是我就用它做了类比。我的实际问题是,第三方提供的DLL的接口函数的参数中含有省略号,而我要对其封装调用。这个DLL属于工控方面的,函数实现向PCI总线发送一些指令,所以显然没法用vsprintf
#3
所以,这个问题的一般性描述就是:如何对含有省略号参数的函数进行封装?(封装它,而不是寻找它的替代物)
#4
如果编译器支持的话,用变长函数模板
不行的话,就用宏吧。其他方法都有限制,不好搞。
#5
直接封装sprintf必须自己解释sFormat参数中的参数个数和类型,否则无法提取参数,然后估计得用汇编重建sprintf的参数表,然后再用汇编调用sprintf
#6
msdn:
va_arg, va_end, va_start
//
int average( int first, ... )
{
int count = 0, sum = 0, i = first;
va_list marker;
va_start( marker, first ); /* Initialize variable arguments. */
while( i != -1 )
{
sum += i;
count++;
i = va_arg( marker, int);
}
va_end( marker ); /* Reset variable arguments. */
return( sum ? (sum / count) : 0 );
}
va_arg, va_end, va_start
//
int average( int first, ... )
{
int count = 0, sum = 0, i = first;
va_list marker;
va_start( marker, first ); /* Initialize variable arguments. */
while( i != -1 )
{
sum += i;
count++;
i = va_arg( marker, int);
}
va_end( marker ); /* Reset variable arguments. */
return( sum ? (sum / count) : 0 );
}
#7
使用特定值(-1)作为可变参数参数表结束,在很多场合不适用,特别是参数类型不一致的时候更是如此
#8
...不定参数不能多级传递. 只有特殊的函数才接收这个外部传递的...参数.
给你个参考:
//注意, ... 可变参数不能传再次传递, 只有v开头的几个特殊函数可以处理.
void _TraceT(LPCTSTR lpszFmt, ...)
{
va_list args;
va_start(args, lpszFmt);
int len = _vsctprintf(lpszFmt, args)+1;
TCHAR *lpszBuf = (TCHAR*)_alloca(len*sizeof(TCHAR));//栈中分配, 不需要释放
_vstprintf_s(lpszBuf, len, lpszFmt, args);
va_end(args);
OutputDebugString(lpszBuf);
}
给你个参考:
//注意, ... 可变参数不能传再次传递, 只有v开头的几个特殊函数可以处理.
void _TraceT(LPCTSTR lpszFmt, ...)
{
va_list args;
va_start(args, lpszFmt);
int len = _vsctprintf(lpszFmt, args)+1;
TCHAR *lpszBuf = (TCHAR*)_alloca(len*sizeof(TCHAR));//栈中分配, 不需要释放
_vstprintf_s(lpszBuf, len, lpszFmt, args);
va_end(args);
OutputDebugString(lpszBuf);
}
#9
" int first"
可以代入: "%d%d%d..."
可以代入: "%d%d%d..."
#10
感谢以上好心人!
average的例子我也看过,但它不比sprintf,再者,我的问题是对含有省略号参数的函数进行直接封装,而不是寻找它的替代物
回楼上:你讲到“不定参数不能多级传递”,那是否意味着我的问题(对含有省略号参数的函数进行直接封装)根本就不成立?
average的例子我也看过,但它不比sprintf,再者,我的问题是对含有省略号参数的函数进行直接封装,而不是寻找它的替代物
回楼上:你讲到“不定参数不能多级传递”,那是否意味着我的问题(对含有省略号参数的函数进行直接封装)根本就不成立?
#11
vsprintf 其实内部是能取得第一个变量的地址,根据地址来取值的。如果你封装 sprintf 则你也得想办法把地址传给它,但实际上 sprintf 只接受值,而不能传递 "..." 处第一个参数的地址进去。
#12
//变长模板参数,需要C++11支持
template<class ... T>
int func( T... v )
{
puts("------");
int r = printf( v... );
puts("======");
return r;
}
//变长参数宏,不一定所有编译器都支持
#define FUNC( ... ) \
{ \
puts("macro ------"); \
printf( __VA_ARGS__ ); \
puts("macro ======"); \
}
int main()
{
func( "%d,%f,%c\n" , 1,2.0 , 'c' );
FUNC( "%d,%f,%c\n" , 1,2.0 , 'c' );
return 0;
}
其他方案都有缺陷...
#13
赞一个
#14
非常感谢大家!
回#12大牛:发帖时为了描述更具体,我用了sprintf,而我实际要封装的函数跟sprintf函数在功能上是完全不同的,它们仅仅是形式一样,即:都是参数列表中带有省略号。我要封装的是第三方提供的DLL里的一个导出函数。不知有没更一般性的方法?谢谢!
回#12大牛:发帖时为了描述更具体,我用了sprintf,而我实际要封装的函数跟sprintf函数在功能上是完全不同的,它们仅仅是形式一样,即:都是参数列表中带有省略号。我要封装的是第三方提供的DLL里的一个导出函数。不知有没更一般性的方法?谢谢!
#15
如果楼主你细心, 已经发现有三种方案了.
还管你是想要自己格式化串, 还是要遍历参数, 都已经给也方案了.
其它的, 还有什么问题吧.
或者你可以再详细的描述下你的问题, 最好是举几个例子, 你想做成什么效果.
还管你是想要自己格式化串, 还是要遍历参数, 都已经给也方案了.
其它的, 还有什么问题吧.
或者你可以再详细的描述下你的问题, 最好是举几个例子, 你想做成什么效果.
#16
回楼上大牛:小弟功力浅显,不能确定你在#12贴的代码是否具有一般性
都怪我提到了sprintf,害了大家去往这个地方思考
我重新描述我的问题吧:
对第三方DLL的一个导出函数(其参数列表中带有省略号)进行封装,要求自己的函数具有与该导出函数一样的参数列表,并且我自己的函数必须去调用该导出函数
导出函数原型:int DLLInterface(char *, const char *, ...);
我的函数原型:int MyDLLInterface(char *, const char *, ...);
要求我的MyDLLInterface必须去调用DLLInterface
int MyDLLInterface(char *, const char *, ...)
{
// do something
DLLInterface(,,...); // 关键就是这里,我必须调用DLLInterface,参数如何传入?
// do something
return 0;
}
请大家抛开sprintf这个函数,我很后悔提到这个函数
谢谢!
都怪我提到了sprintf,害了大家去往这个地方思考
我重新描述我的问题吧:
对第三方DLL的一个导出函数(其参数列表中带有省略号)进行封装,要求自己的函数具有与该导出函数一样的参数列表,并且我自己的函数必须去调用该导出函数
导出函数原型:int DLLInterface(char *, const char *, ...);
我的函数原型:int MyDLLInterface(char *, const char *, ...);
要求我的MyDLLInterface必须去调用DLLInterface
int MyDLLInterface(char *, const char *, ...)
{
// do something
DLLInterface(,,...); // 关键就是这里,我必须调用DLLInterface,参数如何传入?
// do something
return 0;
}
请大家抛开sprintf这个函数,我很后悔提到这个函数
谢谢!
#17
仔细看#12代码,不都实现了么
就算编译器不支持变长模板函数,那也可以写N个模板函数重载,也同样完成目标。
#18
int MyDLLInterface(char *, const char *, ...)
问题是:
第一个 参数 要 指出 有 几个 参数。 否则:
va_arg, va_end, va_start
没法 终止。
引用:
例如 int max(int n, ...); 其函数内部应该如此实现:
#include <iostream.h>
void fun(int a, ...)
{ // 这个 a 是 实际参数 个数
int *temp = &a;
temp++;
for (int i = 0; i < a; ++i)
{
cout << *temp << endl;
temp++;
}
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int d = 4;
fun( 4, a, b, c, d);
system("pause");
return 0;
}
问题是:
第一个 参数 要 指出 有 几个 参数。 否则:
va_arg, va_end, va_start
没法 终止。
引用:
例如 int max(int n, ...); 其函数内部应该如此实现:
#include <iostream.h>
void fun(int a, ...)
{ // 这个 a 是 实际参数 个数
int *temp = &a;
temp++;
for (int i = 0; i < a; ++i)
{
cout << *temp << endl;
temp++;
}
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int d = 4;
fun( 4, a, b, c, d);
system("pause");
return 0;
}
#19
按#12给的不能满足楼主的要求的话,楼主在详细描述下功能需求吧
用宏来做的话,VS2010,GCC编译器都是支持的
#include <iostream>
int DLLInterface(char * output, const char * input, ...)
{
std::cout << "ok" << std::endl;
return(0);
}
#define MyDLLInterface(output, input, ...) \
{ \
std::cout << "in ..." << std::endl; \
DLLInterface(output, input, ##__VA_ARGS__); \
std::cout << "out ..." << std::endl; \
}
int main(int argc, char * argv[])
{
char output[1];
const char * input = "%s %d";
MyDLLInterface(output, input, "test", 1);
return(0);
}
用宏来做的话,VS2010,GCC编译器都是支持的
#20
上面宏的缺陷,没有返回值,
这个可以通过给MyDLLInterface多加一个“输出参数”来完成:
这个可以通过给MyDLLInterface多加一个“输出参数”来完成:
#define MyDLLInterface(ret, output, input, ...) \
do \
{ \
std::cout << "in ..." << std::endl; \
ret = DLLInterface(output, input, ##__VA_ARGS__); \
std::cout << "out ..." << std::endl; \
} while(false)
#21
#22
感谢大家的答复,尤其是akirya的好心相助!
我在VC2010上测试发现它不支持变长模板参数,现在暂用函数重载的方法,好在现在的调用形式不多,只有5、6种。
另外再请教akirya,这个DLL里还有一个导出函数,它的省略号部分可以进行参数带回,请问,这样的函数C++是否也有什么新特性来支持?谢谢!
我在VC2010上测试发现它不支持变长模板参数,现在暂用函数重载的方法,好在现在的调用形式不多,只有5、6种。
另外再请教akirya,这个DLL里还有一个导出函数,它的省略号部分可以进行参数带回,请问,这样的函数C++是否也有什么新特性来支持?谢谢!
#23
仔细看#12代码,函数模板上已经写了。
#24
楼主,我直接封装了这个方法,用作日志记录。一会儿给你代码
#1
应该用 vsprintf
#2
感谢#1朋友,谢谢!
事实上,我在描述问题时进行了类比简化。我的实际问题跟sprintf相似,于是我就用它做了类比。我的实际问题是,第三方提供的DLL的接口函数的参数中含有省略号,而我要对其封装调用。这个DLL属于工控方面的,函数实现向PCI总线发送一些指令,所以显然没法用vsprintf
事实上,我在描述问题时进行了类比简化。我的实际问题跟sprintf相似,于是我就用它做了类比。我的实际问题是,第三方提供的DLL的接口函数的参数中含有省略号,而我要对其封装调用。这个DLL属于工控方面的,函数实现向PCI总线发送一些指令,所以显然没法用vsprintf
#3
所以,这个问题的一般性描述就是:如何对含有省略号参数的函数进行封装?(封装它,而不是寻找它的替代物)
#4
如果编译器支持的话,用变长函数模板
不行的话,就用宏吧。其他方法都有限制,不好搞。
#5
直接封装sprintf必须自己解释sFormat参数中的参数个数和类型,否则无法提取参数,然后估计得用汇编重建sprintf的参数表,然后再用汇编调用sprintf
#6
msdn:
va_arg, va_end, va_start
//
int average( int first, ... )
{
int count = 0, sum = 0, i = first;
va_list marker;
va_start( marker, first ); /* Initialize variable arguments. */
while( i != -1 )
{
sum += i;
count++;
i = va_arg( marker, int);
}
va_end( marker ); /* Reset variable arguments. */
return( sum ? (sum / count) : 0 );
}
va_arg, va_end, va_start
//
int average( int first, ... )
{
int count = 0, sum = 0, i = first;
va_list marker;
va_start( marker, first ); /* Initialize variable arguments. */
while( i != -1 )
{
sum += i;
count++;
i = va_arg( marker, int);
}
va_end( marker ); /* Reset variable arguments. */
return( sum ? (sum / count) : 0 );
}
#7
使用特定值(-1)作为可变参数参数表结束,在很多场合不适用,特别是参数类型不一致的时候更是如此
#8
...不定参数不能多级传递. 只有特殊的函数才接收这个外部传递的...参数.
给你个参考:
//注意, ... 可变参数不能传再次传递, 只有v开头的几个特殊函数可以处理.
void _TraceT(LPCTSTR lpszFmt, ...)
{
va_list args;
va_start(args, lpszFmt);
int len = _vsctprintf(lpszFmt, args)+1;
TCHAR *lpszBuf = (TCHAR*)_alloca(len*sizeof(TCHAR));//栈中分配, 不需要释放
_vstprintf_s(lpszBuf, len, lpszFmt, args);
va_end(args);
OutputDebugString(lpszBuf);
}
给你个参考:
//注意, ... 可变参数不能传再次传递, 只有v开头的几个特殊函数可以处理.
void _TraceT(LPCTSTR lpszFmt, ...)
{
va_list args;
va_start(args, lpszFmt);
int len = _vsctprintf(lpszFmt, args)+1;
TCHAR *lpszBuf = (TCHAR*)_alloca(len*sizeof(TCHAR));//栈中分配, 不需要释放
_vstprintf_s(lpszBuf, len, lpszFmt, args);
va_end(args);
OutputDebugString(lpszBuf);
}
#9
" int first"
可以代入: "%d%d%d..."
可以代入: "%d%d%d..."
#10
感谢以上好心人!
average的例子我也看过,但它不比sprintf,再者,我的问题是对含有省略号参数的函数进行直接封装,而不是寻找它的替代物
回楼上:你讲到“不定参数不能多级传递”,那是否意味着我的问题(对含有省略号参数的函数进行直接封装)根本就不成立?
average的例子我也看过,但它不比sprintf,再者,我的问题是对含有省略号参数的函数进行直接封装,而不是寻找它的替代物
回楼上:你讲到“不定参数不能多级传递”,那是否意味着我的问题(对含有省略号参数的函数进行直接封装)根本就不成立?
#11
vsprintf 其实内部是能取得第一个变量的地址,根据地址来取值的。如果你封装 sprintf 则你也得想办法把地址传给它,但实际上 sprintf 只接受值,而不能传递 "..." 处第一个参数的地址进去。
#12
//变长模板参数,需要C++11支持
template<class ... T>
int func( T... v )
{
puts("------");
int r = printf( v... );
puts("======");
return r;
}
//变长参数宏,不一定所有编译器都支持
#define FUNC( ... ) \
{ \
puts("macro ------"); \
printf( __VA_ARGS__ ); \
puts("macro ======"); \
}
int main()
{
func( "%d,%f,%c\n" , 1,2.0 , 'c' );
FUNC( "%d,%f,%c\n" , 1,2.0 , 'c' );
return 0;
}
其他方案都有缺陷...
#13
赞一个
#14
非常感谢大家!
回#12大牛:发帖时为了描述更具体,我用了sprintf,而我实际要封装的函数跟sprintf函数在功能上是完全不同的,它们仅仅是形式一样,即:都是参数列表中带有省略号。我要封装的是第三方提供的DLL里的一个导出函数。不知有没更一般性的方法?谢谢!
回#12大牛:发帖时为了描述更具体,我用了sprintf,而我实际要封装的函数跟sprintf函数在功能上是完全不同的,它们仅仅是形式一样,即:都是参数列表中带有省略号。我要封装的是第三方提供的DLL里的一个导出函数。不知有没更一般性的方法?谢谢!
#15
如果楼主你细心, 已经发现有三种方案了.
还管你是想要自己格式化串, 还是要遍历参数, 都已经给也方案了.
其它的, 还有什么问题吧.
或者你可以再详细的描述下你的问题, 最好是举几个例子, 你想做成什么效果.
还管你是想要自己格式化串, 还是要遍历参数, 都已经给也方案了.
其它的, 还有什么问题吧.
或者你可以再详细的描述下你的问题, 最好是举几个例子, 你想做成什么效果.
#16
回楼上大牛:小弟功力浅显,不能确定你在#12贴的代码是否具有一般性
都怪我提到了sprintf,害了大家去往这个地方思考
我重新描述我的问题吧:
对第三方DLL的一个导出函数(其参数列表中带有省略号)进行封装,要求自己的函数具有与该导出函数一样的参数列表,并且我自己的函数必须去调用该导出函数
导出函数原型:int DLLInterface(char *, const char *, ...);
我的函数原型:int MyDLLInterface(char *, const char *, ...);
要求我的MyDLLInterface必须去调用DLLInterface
int MyDLLInterface(char *, const char *, ...)
{
// do something
DLLInterface(,,...); // 关键就是这里,我必须调用DLLInterface,参数如何传入?
// do something
return 0;
}
请大家抛开sprintf这个函数,我很后悔提到这个函数
谢谢!
都怪我提到了sprintf,害了大家去往这个地方思考
我重新描述我的问题吧:
对第三方DLL的一个导出函数(其参数列表中带有省略号)进行封装,要求自己的函数具有与该导出函数一样的参数列表,并且我自己的函数必须去调用该导出函数
导出函数原型:int DLLInterface(char *, const char *, ...);
我的函数原型:int MyDLLInterface(char *, const char *, ...);
要求我的MyDLLInterface必须去调用DLLInterface
int MyDLLInterface(char *, const char *, ...)
{
// do something
DLLInterface(,,...); // 关键就是这里,我必须调用DLLInterface,参数如何传入?
// do something
return 0;
}
请大家抛开sprintf这个函数,我很后悔提到这个函数
谢谢!
#17
仔细看#12代码,不都实现了么
就算编译器不支持变长模板函数,那也可以写N个模板函数重载,也同样完成目标。
#18
int MyDLLInterface(char *, const char *, ...)
问题是:
第一个 参数 要 指出 有 几个 参数。 否则:
va_arg, va_end, va_start
没法 终止。
引用:
例如 int max(int n, ...); 其函数内部应该如此实现:
#include <iostream.h>
void fun(int a, ...)
{ // 这个 a 是 实际参数 个数
int *temp = &a;
temp++;
for (int i = 0; i < a; ++i)
{
cout << *temp << endl;
temp++;
}
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int d = 4;
fun( 4, a, b, c, d);
system("pause");
return 0;
}
问题是:
第一个 参数 要 指出 有 几个 参数。 否则:
va_arg, va_end, va_start
没法 终止。
引用:
例如 int max(int n, ...); 其函数内部应该如此实现:
#include <iostream.h>
void fun(int a, ...)
{ // 这个 a 是 实际参数 个数
int *temp = &a;
temp++;
for (int i = 0; i < a; ++i)
{
cout << *temp << endl;
temp++;
}
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int d = 4;
fun( 4, a, b, c, d);
system("pause");
return 0;
}
#19
按#12给的不能满足楼主的要求的话,楼主在详细描述下功能需求吧
用宏来做的话,VS2010,GCC编译器都是支持的
#include <iostream>
int DLLInterface(char * output, const char * input, ...)
{
std::cout << "ok" << std::endl;
return(0);
}
#define MyDLLInterface(output, input, ...) \
{ \
std::cout << "in ..." << std::endl; \
DLLInterface(output, input, ##__VA_ARGS__); \
std::cout << "out ..." << std::endl; \
}
int main(int argc, char * argv[])
{
char output[1];
const char * input = "%s %d";
MyDLLInterface(output, input, "test", 1);
return(0);
}
用宏来做的话,VS2010,GCC编译器都是支持的
#20
上面宏的缺陷,没有返回值,
这个可以通过给MyDLLInterface多加一个“输出参数”来完成:
这个可以通过给MyDLLInterface多加一个“输出参数”来完成:
#define MyDLLInterface(ret, output, input, ...) \
do \
{ \
std::cout << "in ..." << std::endl; \
ret = DLLInterface(output, input, ##__VA_ARGS__); \
std::cout << "out ..." << std::endl; \
} while(false)
#21
#22
感谢大家的答复,尤其是akirya的好心相助!
我在VC2010上测试发现它不支持变长模板参数,现在暂用函数重载的方法,好在现在的调用形式不多,只有5、6种。
另外再请教akirya,这个DLL里还有一个导出函数,它的省略号部分可以进行参数带回,请问,这样的函数C++是否也有什么新特性来支持?谢谢!
我在VC2010上测试发现它不支持变长模板参数,现在暂用函数重载的方法,好在现在的调用形式不多,只有5、6种。
另外再请教akirya,这个DLL里还有一个导出函数,它的省略号部分可以进行参数带回,请问,这样的函数C++是否也有什么新特性来支持?谢谢!
#23
仔细看#12代码,函数模板上已经写了。
#24
楼主,我直接封装了这个方法,用作日志记录。一会儿给你代码