Как предотвратить функцию печати?

Можно ли отключить функцию? Например:

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

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

И вместо:

BLAH!
10

Я бы получил:

10

Возможно ли это? Если позитивно, как это сделать?

Ответ 1

Очень сложный способ сделать почти то, что вы хотите, это использовать системный вызов dup2(). Для этого требуется выполнить fflush(stdout); dup2(silentfd, stdout); до вызова function() и последующего копирования: fflush(stdout); dup2(savedstdoutfd, stdout);. Таким образом, это невозможно сделать как просто silence(function()), так как эта конструкция позволяет выполнять код только после того, как function() уже выполнен.

Дескрипторы файлов silentfd и savedstdoutfd должны быть подготовлены заранее (непроверенный код):

 int silentfd = open("/dev/null",O_WRONLY);
 int savedstdoutfd = dup(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;
}

Ответ 3

Нет, это невозможно. Однако вы можете попытаться временно перенаправить stdout на другое. Это может приблизиться к тому, что вы хотите.

Ответ 4

Вы можете использовать этот макрос вместо printf, чтобы предотвратить печать:

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

затем используйте макрос PRINT, рассматривая переменную flag. Если flag==1, функция будет печататься, и если flag==0, функция не будет печататься.

Ответ 5

Если вы разрабатываете функцию, выполните следующие действия:

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) значение истинно. Мое предположение является склонным к ошибкам, поскольку вам нужно будет подражать подписи printf для silence или для любой другой функции, которую вы хотите использовать.

Ответ 6

С расширения GCC, вы можете подумать о наличии макросов, таких как

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 будет работать, только если его аргумент X является выражением int (или используйте typeof) Я также предполагаю, что результат printf никогда не используется. Напомним, что "рекурсивные" макросы специально предварительно обработаны, внутреннее появление printf (в этом макросе printf) остается дословным без макроразложения.

Обратите внимание, что silence не может быть функцией (иначе его аргумент был бы оценен до его вызова). И вам нужно GCC выражение выражений расширение, чтобы "запомнить" результат аргумента в некоторой переменной _x (вы могли бы сгенерировать это имя, используя __COUNTER__ и конкатенация препроцессора), чтобы вернуть его как значение silence вызова макроса.

Затем вам нужно определить свои функции quiet() и verbose(), возможно, что-то вроде

void quiet() 
{
   silent = true;
}

void verbose()
{
   silent = false,
}

если вы не хотите определять printf как свой макрос, вы можете использовать freopen (3) в stdout ( возможно, с помощью "/dev/null" и т.д.) или dup2 (2) трюки (например предложил Pascal Cuoq).

Если ваша база кода огромна, и вы хотите что-то более серьезное и готовы потратить дни или недели работы, подумайте о настройке своего компилятора GCC с помощью плагина или MELT (или попросите кого-нибудь сделать это). Обратите внимание, что 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, чтобы принять никаких переменных аргументов в переменный макрос. Если вы хотите строгого C99, вы просто скажете __VA_ARGS__, и каждый dbgprintf будет нужен один аргумент после формата.

Вы также можете повторно реализовать свою собственную функцию printf, но я не рекомендую это делать.

(Обратите внимание, что все может быть сложнее, вы можете печатать с помощью fputs not printf....)

Ответ 7

К сожалению, если у вас есть функция, которая явно печатает и вызывает ее так, она всегда будет печататься. если вы хотите полностью отключить эту функцию, вы можете просто прокомментировать эту строку. Вы даже можете использовать оператор управления, чтобы он печатал только IF и когда выполнялось условие, иначе оно остается пустым и возвращает только число.