免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3717 | 回复: 5
打印 上一主题 下一主题

[函数] MyLog( logname, format,...)日志函数变参参数检查问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-10-28 07:37 |只看该作者 |倒序浏览
各位大虾们:
小弟在做开发时候遇到一个说大不大,说小不小的问题,请赐教!
项目里有个记日志的函数,使用了可变参数,原型如下:

int MyLog( char *logname, char *format, ... );
logname:日志文件名
format:格式输入
... :变参输出

使用方法如下:
MyLog( "myserver", "run server @ [%d].pid[%d]\n", time(0), getpid() );

我遇到的问题是,有时候我参数输入不对,例如可能会写成如下:
MyLog( "myserver", "server name [%s]" ); /*漏写了一个参数 */
MyLog( "myserver", "server name [%s]" , getpid()); /*参数不匹配 */

这样程序在运行的时候可能会core出来。

所以我希望在编译的时候就能把这些问题发现。而这些函数在编译的时候如果参数输入错误不会报警告,
这让我觉得很不方便。而小弟发现gcc编译器printf格式输出的时候,如果参数输入错,编译器会警告;所以我的想法
是把MyLog通过宏定义转为printf,MyLog比printf多了一个logname的参数,因此小弟尝试如下操作:

------------------------------------    方法一  -----------------------------------------------------
#define MyLog(a,b,...) printf( b, ... )

这样去掉了第一个参数!

但是这样的变参宏定义,编译器是不支持的!郁闷!


------------------------------------    方法二  -----------------------------------------------------
另外一个方法是把MyLog的第一个参数去掉,
例如MyLog( "myserver", "server name [%s]" ); /*漏写了一个参数 */
转为printf( "server name [%s]" );
这样能把错误都发现,但是要在每个日志输出的地方都要改程序代码,工作量太大!

小弟想要的答案是:
(1)方法一中,有没有宏定义的其他技巧,把 MyLog(a,b,...) 转为printf(b,...) ?
(2)如果采用第二种方法,如何使用sed批量修改日志,例如我有如下的使用在server.c文件中
----server.c----
int main(int argc,char **argv)
{
MyLog( "myserver", "server name [%s]" ); /*漏写了一个参数 */
MyLog( "myserver", "server name [%s]" , getpid()); /*参数不匹配 */
}
使用sed如何去掉转化为如下:
int main(int argc,char **argv)
{
printf( "server name [%s]" ); /*漏写了一个参数 */
printf( "myserver", "server name [%s]" , getpid()); /*参数不匹配 */
}


谢谢!!!!!!!!!!!

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
2 [报告]
发表于 2006-10-28 08:56 |只看该作者
两个方法:
1,用 GCC 的扩展宏来实现格式串的检查。
2,#define MyLog(a,b,...) printf( b, ... ) 应该写成 #define MyLog(a,b,...) printf( b, __VA_ARGS__ )

下面给出一个例子来演示这两种技巧:
  1. flw@Sleeper:~$ cat ttt.c
  2. # include <stdio.h>
  3. # include <stdarg.h>
  4. # include <argp.h>

  5. # define FOO(...) printf( "foo: " __VA_ARGS__ );

  6. int foo( const char *logFileName, __const char *fmt, ... )
  7.      __attribute__ ((__format__ (__printf__, 2, 3)));

  8. int main( void )
  9. {
  10.     FOO( "hello, [%d]\n", "flw" );
  11.     foo( "foo.txt", "hello, [%d]\n", "flw" );
  12.     return 1;
  13. }

  14. int foo( const char *logFileName, __const char *fmt, ... )
  15. {
  16.     FILE *fp;

  17.     fp = fopen( logFileName, "a+" );
  18.     if ( fp != NULL ){
  19.         va_list args;
  20.         int ret;

  21.         va_start( args, fmt );
  22.         ret = fprintf( fp, fmt, args );
  23.         va_end( args );
  24.         fclose(fp);
  25.         return ret;
  26.     }

  27.     return 0;
  28. }
  29. flw@Sleeper:~$ rm -f foo.txt
  30. flw@Sleeper:~$ cc -Wall -o ttt ttt.c
  31. ttt.c: In function 'main':
  32. ttt.c:12: warning: format '%d' expects type 'int', but argument 2 has type 'char *'
  33. ttt.c:13: warning: format '%d' expects type 'int', but argument 3 has type 'char *'
  34. flw@Sleeper:~$ ./ttt
  35. foo: hello, [134514120]
  36. flw@Sleeper:~$ cat foo.txt
  37. hello, [-1342754408]
  38. flw@Sleeper:~$
复制代码

[ 本帖最后由 flw 于 2006-10-28 21:43 编辑 ]

论坛徽章:
5
IT运维版块每日发帖之星
日期:2015-08-06 06:20:00IT运维版块每日发帖之星
日期:2015-08-10 06:20:00IT运维版块每日发帖之星
日期:2015-08-23 06:20:00IT运维版块每日发帖之星
日期:2015-08-24 06:20:00IT运维版块每日发帖之星
日期:2015-11-12 06:20:00
3 [报告]
发表于 2006-10-28 10:08 |只看该作者
fprintf不行吗?

论坛徽章:
0
4 [报告]
发表于 2006-10-28 10:51 |只看该作者
vprintf 行不?只有两个参数

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2006-10-28 21:44 |只看该作者
楼主看看我在二楼的回复。

论坛徽章:
0
6 [报告]
发表于 2006-10-29 20:47 |只看该作者
谢谢了!
大法师果然就是牛,领教!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP