简体   繁体   中英

How to prevent function from printing?

Is it possible to silence a function? For example:

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

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

And instead of:

BLAH!
10

I would get:

10

Is it possible? If positive how to do it?

An awfully complicated way to do almost what you want is to use the dup2() system call. This requires executing fflush(stdout); dup2(silentfd, stdout); fflush(stdout); dup2(silentfd, stdout); before function() is called, and copying back afterwards: fflush(stdout); dup2(savedstdoutfd, stdout); fflush(stdout); dup2(savedstdoutfd, stdout); . So it is not possible to do as just silence(function()) , since this construct only allows to execute code after function() has already been executed.

The file descriptors silentfd and savedstdoutfd have to be prepared in advance (untested code):

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

This is almost certainly not what you really want, but inasmuch as your question is phrased as “is it possible?”, the answer is “almost”.

use macro function and null device.

Eg for windows

#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;
}

No its not possible. You could however try to temporarily redirect the stdout to something else. That may come close to what you want.

You can use this macro instead of printf to be able to prevent printing:

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

then use PRINT macro by considering the variable flag . If flag==1 , the function will print and if flag==0 , the function will not print.

If you're designing the function do the following:

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;
}

That should do what you're looking for. Unfortunately, I didn't test it and my C is probably a little bit rusty.

Of course if function isn't something you have control over, the answers already posted are all correct solutions.


Actually, if you're designing the function yourself, just do:

int function(int print){
    if (print)
       printf("BLAH!");

    return 10;
}


function(0);  /* Won't print anything */
function(!0);  /* Will print "BLAH!" */

because 0 is false and any non-zero (or !0 ) value is true. My above suggestion is error prone since you'll have to be able to mimic the printf signature for silence or for any other function you wish to use.

With GCC extensions , you might consider having macros like

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

that silence macro would work only if its argument X is a int expression (or use typeof ) I also assume that the result of printf is never used. Recall that "recursive" macros are specially pre-processed, the inside occurrence of printf (in that printf macro) is left verbatim without macro-expansion.

Notice that silence cannot be a function (otherwise, its argument would have been evaluated before calling it). And you need GCC statement expressions extension to "remember" the result of the argument in some variable _x (you could generate that name using__COUNTER__ and preprocessor concatenation), to give it back as the value of silence macro invocation.

Then you need to define your functions quiet() and verbose() , perhaps something like

void quiet() 
{
   silent = true;
}

void verbose()
{
   silent = false,
}

if you don't want to define printf as your macro, you could use freopen(3) on stdout (perhaps with "/dev/null" etc...) or do dup2(2) tricks (like suggested by Pascal Cuoq ).

If your code base is huge, and you want something more serious and are willing to spend days or weeks of work, consider customizing your GCC compiler with a plugin or a MELT extension (or ask someone to do it). Notice that printf is known to GCC.

In reality, you should define your own macro like

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

and just use myprintf instead of printf everywhere, this is a portable trick. Of course, I assume you are not passing printf as a function pointer.

For debugging, I actually recommend

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

and then I use dbgprintf("i=%d",i) or simply dbgprintf("foo here") in my code.

I'm using ##__VA_ARGS__ which is a GCC extension to accept no variable arguments to a variadic macro. If you want strict C99, you will just say __VA_ARGS__ and every dbgprintf would need one argument after the format.

You could also re-implement your own printf function, but I don't advise doing that.

(Notice that things could be more complex, you can print using fputs not printf ....)

Unfortunately if you have the function explicitly printing and call it like this then it will always print. if you want to silence the function completely you could simply comment out that line.You could even use a control statement so that it only prints IF and when a condition is met otherwise it stays blank and only returns the number.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM