【问题标题】:How to use Variadic macros with fprintf如何在 fprintf 中使用可变参数宏
【发布时间】:2014-10-10 17:40:55
【问题描述】:

我正在尝试通过编写宏将日志打印到文件中。 我的宏如下图所示:

#define LOG(fmt,...){\
    FILE *F;\
    F = fopen("output.txt","a");\
    fprintf(F,fmt " %s %d",__VA_ARGS__,__FILE__,__LINE__);}

我打算用以下格式调用LOG:

LOG("values are : %d %d",num1,num2);

但是当我编译时我得到了错误

error: expected expression before ‘,’ token
     fprintf(F,fmt " %s %d",__VA_ARGS__,__FILE__,__LINE__);}

谁能解释一下我哪里出错了?

【问题讨论】:

  • 你知道__FILE__char[],而不是int,对吧?与您的问题无关,我真诚地希望在 真实 代码中的某处有一个 fclose(),否则您会像筛子泄漏雨水一样泄漏流指针。
  • 看看这个问题。适用于 C 和 C++。 stackoverflow.com/questions/1056411/…
  • @WhozCraig 是的,很抱歉那里的错误。主程序中有fclose。匆忙复制粘贴错过了:-)
  • @NiklasHansson 感谢您的链接。我会检查一下:)
  • 我知道这可能是一个愚蠢的问题,但我得问。你的工具链支持可变参数宏,对吗?

标签: c printf c-preprocessor variadic variadic-macros


【解决方案1】:

首先你必须将你的宏包装到一个do-while循环中,这样它就会被正确的表达式处理。

#define LOG( fmt , ... ) do{  }while(0)

然后你必须确保 fopen() 调用成功并且在使用后关闭文件。

FILE* f = fopen( "output.txt" , "a" ) ;
if( !f )
    break ;    //break works because you are in a loop
fclose( f ) ;    //also flushes the stream

然后将打印包含在完整的宏中。

#define LOG( fmt , ... )    \
        do{ \
            FILE* f = fopen( "output.txt" , "a" ) ; \
            if( !f )    \
                break ; \
            fprintf(f, fmt" %s %d\n",__VA_ARGS__,__FILE__,__LINE__);    \
            fclose( f ) ;   \
        }while( 0 )

调用格式为:

LOG("values are : %d %d",4444,55555);

您必须输入至少一个正确的可选参数,并在字符串中带有相应的标志。

【讨论】:

  • 我将 VA_ARGS 替换为 ##__VA_ARGS__ 并开始工作。谢谢 :) 我不明白为什么需要循环。当循环不存在时会发生什么?
  • @user1692342 您的代码已经正确(有一些问题),##__VA_ARGS__ 是编译器扩展。
  • @user1692342 宏可能无法正确处理。在使用 if 语句时尝试几个有和没有 do-while 的例子,你会发现代码在某些情况下会被破坏。
  • "##__VA_ARGS__ 是一个编译器扩展。" ——哇,很高兴知道。我认为预处理器的行为或多或少是通用的,环境探测主要用于为编译器启用与平台无关的代码。当您说它是编译器扩展时,您的意思是包含##a b c 的预处理文件在编译期间变为a,还是您通俗地使用“编译器”来表示整个管道?
【解决方案2】:
#define LOG(fmt,...){\
    FILE *F;\
    F = fopen("output.txt","a");\
    fprintf(F,fmt " %d %d",__VA_ARGS__,__FILE__,__LINE__);}

多个问题

  1. 你永远不会fcloseF.
  2. __FILE__ 是一个字符串。
  3. 如果你希望能够在没有参数的情况下调用它__VA_ARGS__必须在最后...
  4. ...或者使用这个小技巧:

    #define LOG(fmt,...){\
        FILE *F;\
        F = fopen("output.txt","a");\
        fprintf(F,fmt " %s %d", ##__VA_ARGS__, __FILE__,__LINE__);}
    

##__VA_ARGS__ 是一个 GCC 扩展,如果没有参数,它会删除前面的逗号)。

还可以查看 this answer 关于“自定义”类似 printf 的函数。

【讨论】:

  • 我试过你的代码:出现以下错误:错误:','标记之前的预期表达式#define VA_ARG(...),##__VA_ARGS__ 注意:在宏'VA_ARG'fprintf( F,fmt " %s %d", VA_ARG(VA_ARGS),FILE,LINE);}
  • 哦,是的,我忘了。这是一个 GCC 扩展。我的错。我发布的代码中还有另一个错误,现在已修复。
  • 如果我传递了参数,它可以工作:) 如果没有参数,则打印垃圾值:(
猜你喜欢
  • 1970-01-01
  • 2017-11-08
  • 1970-01-01
  • 1970-01-01
  • 2018-02-07
  • 1970-01-01
  • 2018-01-13
  • 2010-10-15
  • 1970-01-01
相关资源
最近更新 更多