【问题标题】:How to prevent function from printing?如何防止功能打印?
【发布时间】:2013-05-11 14:50:47
【问题描述】:

是否可以静音一个函数? 例如:

#include <stdio.h>
int function(){
  printf("BLAH!");
  return 10;

}
int main(){
  printf("%d", silence( function()) );
return 0;
}

而不是:

BLAH!
10

我会得到:

10

有可能吗?如果阳性怎么办?

【问题讨论】:

  • 不要调用函数...你的意图是什么?
  • 它是软件,几乎一切皆有可能。你想要一个功能吗?还是可以接受预处理器方法?在运行时修改代码怎么样?
  • chat.stackoverflow.com/rooms/29552/c(让我们在那边讨论,好吗?):)
  • 在解释型语言中,将 printf 替换为不执行任何操作/输出到文件/缓冲区的其他函数将是微不足道的......
  • 您可以使用不同的输出流,例如将fprintf(stderr,...) 用于您希望能够丢弃的消息,将fprintf(stdout,...) 用于其他消息。

标签: c gcc printf


【解决方案1】:

使用dup2() 系统调用几乎可以完成您想要的操作。这需要在调用function() 之前执行fflush(stdout); dup2(silentfd, stdout);,然后再复制回来:fflush(stdout); dup2(savedstdoutfd, stdout);。所以不可能像silence(function())那样做,因为这个结构只允许在function()已经被执行之后执行代码。

文件描述符silentfdsavedstdoutfd要提前准备好(未经测试的代码):

 int silentfd = open("/dev/null",O_WRONLY);
 int savedstdoutfd = dup(stdout);

这几乎肯定不是您真正想要的,但只要您的问题被表述为“有可能吗?”,答案就是“几乎”。

【讨论】:

  • 从技术上讲,您可以在 C 中编写 C 解释器,让解释器执行函数,然后忽略函数中的所有 printfs。所以当然答案是“是”,图灵完备性要求它。
  • @PascalCuoq 为什么可以在传递给silence之前对其进行评估以运行?
  • @BLUEPIXY 啊,是的,你提出了一个很好的观点,即使dup2() 也不完全允许 ​​OP 想要做的事情,那就是写 silence(f())f 沉默。我会在我的回答中加入这种细微差别。
  • silence 可以变成宏。
  • @BasileStarynkevitch 我采纳了这个建议并尝试扩展如何准备savedstdoutfd,但您确定您的建议中的O_RDONLY 部分吗?我本来希望 O_WRONLY 更接近地模仿 stdout
【解决方案2】:

使用宏功能和空设备。

例如窗户

#include <stdio.h>

#define silence(x) (_stream = freopen("NUL:", "w", stdout), _ret_value = x,_stream = freopen("CON:", "w", stdout),_ret_value)
int _ret_value;
FILE *_stream;

int function(){
  printf("BLAH!");
  return 10;

}
int main(void){
    printf("%d", silence( function()) );
    return 0;
}

【讨论】:

  • 宏函数不是函数。这只是外观。
  • 首先是函数旁边的一对多右括号。其次,对于 UNIX,准确地说,SunOS 可能是正确的宏版本。第三个是完整的代码示例。
  • 我认为*nix的环境测试因为Windows环境不能但是(其他人也写过)并且可以做同样的事情。
【解决方案3】:

不,这是不可能的。但是,您可以尝试将标准输出临时重定向到其他内容。这可能会接近你想要的。

【讨论】:

    【解决方案4】:

    您可以使用此宏代替printf 来防止打印:

    int flag=0;
    #define PRINT(...) if(flag){printf(...)}
    

    然后通过考虑变量flag 来使用PRINT 宏。如果flag==1,函数会打印,如果flag==0,函数不会打印。

    【讨论】:

      【解决方案5】:

      使用GCC extensions,您可能会考虑使用类似的宏

      bool silent;
      #define silence(X) ({int _x; quiet(); _x = (X); verbose(); _x; })
      #define printf(Fmt,...) \
        do{if (!silent) printf(Fmt,##__VA_ARGS__);}while(0)
      

      silence 宏只有在其参数Xint 表达式(或使用typeof)时才有效。我还假设从未使用过printf 的结果。回想一下,“递归”宏是经过特殊预处理的,printf(在那个 printf 宏中)的内部出现是逐字保留的,没有宏扩展。

      注意silence 不能是一个函数(否则,它的参数会在调用它之前进行评估)。并且您需要 GCC statement expressions 扩展来“记住”某个变量 _x 中的参数结果(您可以使用 __COUNTER__ 和预处理器连接生成该名称),将其作为 silence 宏的值返回调用。

      然后你需要定义你的函数quiet()verbose(),也许是这样的

      void quiet() 
      {
         silent = true;
      }
      
      void verbose()
      {
         silent = false,
      }
      

      如果您不想将printf 定义为您的宏,您可以在stdout 上使用freopen(3)(可能与"/dev/null" 等...)或使用dup2(2) 技巧(如suggested by Pascal Cuoq )。

      如果您的代码库很大,并且您想要一些更严肃的事情并且愿意花费数天或数周的工作,请考虑使用插件或 MELT 扩展名定制您的 GCC 编译器(或请人这样做)。请注意,printf 是 GCC 已知的。

      实际上,您应该定义自己的宏

      #define myprintf(Fmt, ...) do{if (!silent) \
          printf(Fmt,__VA_ARGS__);}while(0)
      

      并且在任何地方都使用myprintf 而不是printf,这是一个可移植的技巧。当然,我假设您没有将printf 作为函数指针传递。

      为了调试,其实我推荐

      #define dbgprintf(Fmt,...) do{if (wantdebug) \
        printf("%s:%d:" Fmt "\n", __FILE__, __LINE__, \
                ##__VA_ARGS__);}while(0)
      

      然后我在我的代码中使用dbgprintf("i=%d",i) 或简单地使用dbgprintf("foo here")

      我正在使用##__VA_ARGS__,这是一个 GCC 扩展,用于接受 no variable arguments 到可变参数宏。如果你想要严格的 C99,你只需要说 __VA_ARGS__ 并且每个 dbgprintf 在格式后面都需要一个参数。

      您也可以重新实现自己的 printf 函数,但我不建议这样做。

      (请注意,事情可能更复杂,您可以使用fputs 而不是printf ....)

      【讨论】:

      • printf("BLAH!"); 扩展为 printf("BLAH!",); 。我无法编译错误。
      【解决方案6】:

      如果您正在设计函数,请执行以下操作:

      int function(void (*printer)(char *)){
          if (!printer)
              printer = printf;
      
          printer("BLAH!");
          return 10;
      }
      
      void silence(char *s){
          return;
      }
      
      int main(int argc, char **argv){
          printf("%d\n", function(silence));
          return 0;
      }
      

      这应该可以满足您的需求。不幸的是,我没有测试它,我的 C 可能有点生锈了。

      当然,如果function 不是您可以控制的,那么已经发布的答案都是正确的解决方案。


      实际上,如果您自己设计函数,只需这样做:

      int function(int print){
          if (print)
             printf("BLAH!");
      
          return 10;
      }
      
      
      function(0);  /* Won't print anything */
      function(!0);  /* Will print "BLAH!" */
      

      因为0 为假且任何非零(或!0)值为真。我的上述建议很容易出错,因为您必须能够为 silence 或您希望使用的任何其他功能模仿 printf 签名。

      【讨论】:

      • 我正在处理协作项目,因此有些功能我无法编辑,但对于某些我可能会应用此工作。
      • 如果您将函数用作库的一部分,则该库应该从不打印任何内容。需要打印的所有内容都应由用户执行。随意对图书馆作者大喊大叫。此外,某些功能通常应该解耦以提供可重用性。祝你项目好运。
      【解决方案7】:

      不幸的是,如果您有明确打印的函数并像这样调用它,那么它将始终打印。如果您想完全使函数静音,您可以简单地注释掉该行。您甚至可以使用控制语句,使其仅打印 IF 并且在满足条件时,否则它将保持空白并仅返回数字。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-05
        • 2012-10-10
        • 1970-01-01
        • 2014-12-09
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多