Как предотвратить функцию печати?
Можно ли отключить функцию?
Например:
#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 и когда выполнялось условие, иначе оно остается пустым и возвращает только число.