2013-05-11 28 views
12

È possibile eseguire il silenzio? Per esempio:Come impedire la funzione dalla stampa?

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

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

E invece di:

BLAH! 
10 

avrei ricevuto:

10 

E 'possibile? Se positivo come farlo?

+3

Non chiamare la funzione di ... Qual è la vostra intenzione? –

+1

È un software, quasi tutto è possibile. Vuoi una funzione? O è accettabile un metodo per il preprocessore? Che ne dici di modificare il codice in fase di runtime? –

+0

http://chat.stackoverflow.com/rooms/29552/c (Discutiamo laggiù, sì?) :) – cipher

risposta

10

Un modo molto complicato per fare quasi quello che vuoi è utilizzare la chiamata di sistema dup2(). Ciò richiede l'esecuzione di fflush(stdout); dup2(silentfd, stdout); prima della chiamata a function() e la successiva copia: fflush(stdout); dup2(savedstdoutfd, stdout);. Quindi non è possibile fare come solo silence(function()), poiché questo costrutto consente solo di eseguire il codice dopo che function() è già stato eseguito.

I descrittori di file silentfd e savedstdoutfd devono essere preparati in anticipo (codice non testato):

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

Questo non è quasi certamente ciò che si vuole veramente, ma nella misura in cui la tua domanda è formulata come “è possibile ? ", La risposta è" quasi ".

+1

Tecnicamente, è possibile programmare un interprete C in C, fare in modo che l'interprete esegua la funzione e ignorare tutti i 'printf's all'interno della funzione. Quindi, naturalmente, la risposta è "sì", la completezza di Turing lo impone. –

+0

@PascalCuoq Perché può essere valutato per essere eseguito prima che venga passato a 'silence'? – BLUEPIXY

+0

@BLUEPIXY Ah, sì, si alza un buon punto, anche 'dup2()' non consente proprio ciò che l'OP vorrebbe fare, cioè scrivere 'silence (f())' per silenziare 'f'. Incorporerò questa sfumatura nella mia risposta –

0

Sfortunatamente se si dispone della funzione di stampa esplicita e la si chiama così, verrà sempre stampata. se vuoi disattivare completamente la funzione, puoi semplicemente commentare quella linea. Potresti anche usare un'istruzione di controllo in modo che stampi solo IF e quando viene soddisfatta una condizione, altrimenti rimane vuota e restituisce solo il numero.

5

Non è possibile. Puoi comunque provare a reindirizzare temporaneamente lo stdout a qualcos'altro. Potrebbe avvicinarsi a quello che vuoi.

5

È possibile utilizzare questa macro invece di printf per essere in grado di impedire la stampa:

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

quindi utilizzare STAMPA macro considerando la variabile flag. Se flag==1, la funzione verrà stampata e se flag==0, la funzione non verrà stampata.

8

utilizza la funzione macro e il dispositivo nullo.

E.g. per le finestre

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

La funzione macro non è una funzione. È solo l'apparenza. – BLUEPIXY

+0

Prima di tutto una parentesi chiusa accanto alla funzione. Seconda cosa potrebbe essere la versione macro corretta per UNIX, SunOS per essere precisi. E terzo per un esempio di codice completo. – PovilasID

+0

Penso che il test dell'ambiente per * nix perché l'ambiente Windows non può essere ma (altre persone hanno anche scritto) e può fare la stessa cosa. – BLUEPIXY

3

Se si sta progettando la funzione di eseguire le seguenti operazioni:

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

Questo dovrebbe fare quello che stai cercando. Sfortunatamente, non l'ho provato e la mia C è probabilmente un po 'arrugginita.

Ovviamente se function non è qualcosa su cui si ha il controllo, le risposte già pubblicate sono tutte soluzioni corrette.


In realtà, se si sta progettando la funzione da soli, basta fare:

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

    return 10; 
} 


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

perché 0 è falso e qualsiasi valore diverso da zero (o !0) è vero. Il mio suggerimento sopra riportato è soggetto ad errori poiché dovrai essere in grado di simulare la firma printf per silence o per qualsiasi altra funzione che desideri utilizzare.

+0

Sto lavorando al progetto di collaborazione, quindi ci sono funzioni che non posso modificare, ma per alcune probabilmente applicherò questo lavoro. – PovilasID

+0

Se si utilizza la funzione come parte di una libreria, tale libreria dovrebbe * mai * stampare nulla. Tutto ciò che deve essere stampato deve essere eseguito dall'utente. Sentiti libero di urlare all'autore della biblioteca. Inoltre, alcune funzionalità generalmente dovrebbero essere disaccoppiate per fornire la riusabilità. Buona fortuna con il progetto però. –

3

Con GCC extensions, si potrebbe prendere in considerazione che le macro come

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

che silence macro avrebbe funzionato solo se il suo argomento X è un'espressione int (o usare typeof) Suppongo inoltre che il risultato di printf non è mai Usato. Ricordiamo che le macro "ricorsive" sono appositamente pre-elaborate, l'occorrenza interna di printf (in quella macro printf) è lasciata testualmente senza macroespansione.

noti che silence non può essere una funzione (in caso contrario, il suo argomento sarebbe stata valutata prima di chiamare). E hai bisogno dell'estensione GCC statement expressions per "ricordare" il risultato dell'argomento in alcune variabili _x (potresti generare quel nome usando __COUNTER__ e la combinazione del preprocessore), per restituirlo come valore della chiamata di macro silence.

allora avete bisogno di definire le funzioni e le quiet()verbose(), forse qualcosa di simile

void quiet() 
{ 
    silent = true; 
} 

void verbose() 
{ 
    silent = false, 
} 

se non si desidera definire printf come la macro, è possibile utilizzare il freopen(3)stdout (magari con "/dev/null" etc. ..) o fare trucchi dup2(2) (come suggested by Pascal Cuoq).

Se la base di codice è enorme, e si desidera qualcosa di più serio e sono disposti a spendere giorni o settimane di lavoro, considerano la personalizzazione del compilatore GCC con un plugin o un'estensione MELT (o chiedere a qualcuno di farlo). Si noti che printf è noto a GCC.

In realtà, si dovrebbe definire il proprio macro come

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

e basta usare myprintf invece di printf ovunque, questo è un trucco portatile. Naturalmente, presumo che non stiate passando a printf come puntatore a funzione.

Per il debug, in realtà ho consiglio

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

e poi io uso dbgprintf("i=%d",i) o semplicemente dbgprintf("foo here") nel mio codice.

Sto usando ##__VA_ARGS__ che è un'estensione GCC per accettare no variable arguments in una macro variabile. Se si desidera un C99 rigoroso, si dirà semplicemente __VA_ARGS__ e ogni dbgprintf avrà bisogno di un argomento dopo il formato.

È anche possibile ri-implementare la propria funzione printf, ma non è consigliabile farlo.

(Si noti che le cose potrebbero essere più complesse, è possibile stampare utilizzando fputs non printf ....)

+1

'printf (" BLAH! ");' È espanso come 'printf (" BLAH! ",);'. Non riesco a compilare con un errore. – BLUEPIXY

+0

Siamo spiacenti, è necessario '## __ VA_ARGS__' .. corretto ... –

+0

È perfetto. Grazie. – BLUEPIXY

Problemi correlati