Spesso, oltre a fornire una dichiarazione di funzione, le intestazioni standard C possono fornire una "macro di mascheramento" per rendere le cose più veloci. Per esempio, se includo ctype.h
, il file di intestazione dichiareràEsistono restrizioni allo standard C che consentono di implementare le funzioni come macro?
int isdigit(int c);
Ma può anche mascherare la dichiarazione con una macro. Credo che questo è un portatile isdigit
macro secondo lo standard C:
#define isdigit(c) ((c) >= '0' && (c) <= '9')
Naturalmente, questa macro è anche pericolosa, perché introduce un comportamento indefinito se fate questo mentre la macro viene definita:
int c = 'A';
printf("%d\n", isdigit(c++));
Per evitare UB in questo caso ipotetico, devo circondare il nome della funzione con Parens: (isdigit)(c++)
. Quindi, la mia domanda è: ci sono restrizioni sul tipo di macro di mascheratura che può essere definita da un'intestazione standard? Sono garantiti per non causare un comportamento indefinito se un'espressione di argomento ha effetti collaterali, o tecnicamente sono autorizzati a comportarsi in modo strano, come vediamo sopra? Dove sono i limiti?
La macro proposta non è conforme. Con le eccezioni delle implementazioni macro (opzionali) delle funzioni 'getc()' e 'putc()', una macro definizione di una funzione standard potrebbe non valutare nessuno dei suoi argomenti più di una volta. Se invocato come 'isdigit (C++)' la macro si comporta male, ma l'istruzione funziona correttamente con macro conformi e con una funzione. –
Mi spiace, cosa intendi per "macro standard"? In ogni caso, quando ho detto "portatile", intendevo "ben educato su tutti i compilatori C conformi agli standard", quando ho passato un argomento appropriato senza effetti collaterali. –
Lo standard C afferma che qualsiasi funzione standard può anche essere implementata come macro. Ma richiede anche che qualsiasi implementazione macro di qualsiasi funzione C standard (eccetto 'getc()' e 'putc()') debba solo valutare i suoi argomenti una volta, perché la macro deve comportarsi esattamente come se fosse una funzione. Inoltre, ogni funzione deve essere dichiarata e implementata come una funzione in modo che il suo indirizzo possa essere preso e passato come un puntatore alla funzione. Questo è praticamente l'informazione che Paul Griffiths ti ha citato dallo standard. Si noti che 'setjmp()' è esplicitamente una macro. –