请教大牛!如何封装sprintf?很急!!

ylyan20xx 2014-02-09 07:46:48
工作中遇到的问题,实现mysprintf对sprintf的封装
要求mysprintf的参数列表必须与sprintf一致,即int mysprintf(char *, const char *, ...)
也就是原有代码中对sprintf的调用可直接用mysprintf进行替换
必须强调一点(请大家注意审题):不是自己写一个函数来sprintf的功能,而是对其封装,即
int mysprintf(char *, const char *, ...)
{
// do something
sprintf(,,...); // 关键就是这里,如何解析mysprintf的传入参数并传给sprintf,这包括个数、类型等待
// do something
return len;
}
小弟在此谢谢了!
...全文
551 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
grf9527 2014-02-13
  • 打赏
  • 举报
回复
楼主,我直接封装了这个方法,用作日志记录。一会儿给你代码
  • 打赏
  • 举报
回复
引用 22 楼 ylyan20xx 的回复:
感谢大家的答复,尤其是akirya的好心相助! 我在VC2010上测试发现它不支持变长模板参数,现在暂用函数重载的方法,好在现在的调用形式不多,只有5、6种。 另外再请教akirya,这个DLL里还有一个导出函数,它的省略号部分可以进行参数带回,请问,这样的函数C++是否也有什么新特性来支持?谢谢!
仔细看#12代码,函数模板上已经写了。
ylyan20xx 2014-02-11
  • 打赏
  • 举报
回复
回楼上大牛:小弟功力浅显,不能确定你在#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这个函数,我很后悔提到这个函数 谢谢!
ylyan20xx 2014-02-11
  • 打赏
  • 举报
回复
感谢大家的答复,尤其是akirya的好心相助! 我在VC2010上测试发现它不支持变长模板参数,现在暂用函数重载的方法,好在现在的调用形式不多,只有5、6种。 另外再请教akirya,这个DLL里还有一个导出函数,它的省略号部分可以进行参数带回,请问,这样的函数C++是否也有什么新特性来支持?谢谢!
xiaohuh421 2014-02-11
  • 打赏
  • 举报
回复
如果楼主你细心, 已经发现有三种方案了. 还管你是想要自己格式化串, 还是要遍历参数, 都已经给也方案了. 其它的, 还有什么问题吧. 或者你可以再详细的描述下你的问题, 最好是举几个例子, 你想做成什么效果.
ken_scott 2014-02-11
  • 打赏
  • 举报
回复
上面宏的缺陷,没有返回值, 这个可以通过给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)
ken_scott 2014-02-11
  • 打赏
  • 举报
回复
按#12给的不能满足楼主的要求的话,楼主在详细描述下功能需求吧

#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编译器都是支持的
schlafenhamster 2014-02-11
  • 打赏
  • 举报
回复
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; }
  • 打赏
  • 举报
回复
引用 16 楼 ylyan20xx 的回复:
回楼上大牛:小弟功力浅显,不能确定你在#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这个函数,我很后悔提到这个函数 谢谢!
仔细看#12代码,不都实现了么 就算编译器不支持变长模板函数,那也可以写N个模板函数重载,也同样完成目标。
xiaohuh421 2014-02-10
  • 打赏
  • 举报
回复
...不定参数不能多级传递. 只有特殊的函数才接收这个外部传递的...参数. 给你个参考: //注意, ... 可变参数不能传再次传递, 只有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); }
worldy 2014-02-10
  • 打赏
  • 举报
回复
引用 6 楼 schlafenhamster 的回复:
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 ); }
使用特定值(-1)作为可变参数参数表结束,在很多场合不适用,特别是参数类型不一致的时候更是如此
worldy 2014-02-10
  • 打赏
  • 举报
回复
直接封装sprintf必须自己解释sFormat参数中的参数个数和类型,否则无法提取参数,然后估计得用汇编重建sprintf的参数表,然后再用汇编调用sprintf
ylyan20xx 2014-02-10
  • 打赏
  • 举报
回复
非常感谢大家! 回#12大牛:发帖时为了描述更具体,我用了sprintf,而我实际要封装的函数跟sprintf函数在功能上是完全不同的,它们仅仅是形式一样,即:都是参数列表中带有省略号。我要封装的是第三方提供的DLL里的一个导出函数。不知有没更一般性的方法?谢谢!
schlafenhamster 2014-02-10
  • 打赏
  • 举报
回复
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 ); }
ken_scott 2014-02-10
  • 打赏
  • 举报
回复
引用 12 楼 akirya 的回复:

//变长模板参数,需要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;
}
赞一个
  • 打赏
  • 举报
回复
引用 10 楼 ylyan20xx 的回复:
感谢以上好心人! average的例子我也看过,但它不比sprintf,再者,我的问题是对含有省略号参数的函数进行直接封装,而不是寻找它的替代物 回楼上:你讲到“不定参数不能多级传递”,那是否意味着我的问题(对含有省略号参数的函数进行直接封装)根本就不成立?
//变长模板参数,需要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;
}
其他方案都有缺陷...
「已注销」 2014-02-10
  • 打赏
  • 举报
回复
vsprintf 其实内部是能取得第一个变量的地址,根据地址来取值的。如果你封装 sprintf 则你也得想办法把地址传给它,但实际上 sprintf 只接受值,而不能传递 "..." 处第一个参数的地址进去。
ylyan20xx 2014-02-10
  • 打赏
  • 举报
回复
感谢以上好心人! average的例子我也看过,但它不比sprintf,再者,我的问题是对含有省略号参数的函数进行直接封装,而不是寻找它的替代物 回楼上:你讲到“不定参数不能多级传递”,那是否意味着我的问题(对含有省略号参数的函数进行直接封装)根本就不成立?
schlafenhamster 2014-02-10
  • 打赏
  • 举报
回复
" int first" 可以代入: "%d%d%d..."
  • 打赏
  • 举报
回复
引用 3 楼 ylyan20xx 的回复:
所以,这个问题的一般性描述就是:如何对含有省略号参数的函数进行封装?(封装它,而不是寻找它的替代物)
如果编译器支持的话,用变长函数模板 不行的话,就用宏吧。其他方法都有限制,不好搞。
加载更多回复(3)

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧