2014-12-27 12 views
44

Perché le espressioni costanti nei file di intestazione GCC sono racchiuse tra parentesi, come questa?Così tante parentesi nelle intestazioni standard di gcc

#define INTMAX_MIN (-9223372036854775807LL) 
#define INTMAX_MAX (9223372036854775807LL) 

Quale sarebbe la differenza se ometto le parentesi, in questo modo?

#define INTMAX_MIN -9223372036854775807LL 
#define INTMAX_MAX 9223372036854775807LL 

E perché è presente il suffisso "L"? Sarebbe lo stesso se scrissi quanto segue?

#define INTMAX_MIN -9223372036854775807 
#define INTMAX_MAX 9223372036854775807 

Esiste un'utilità reale o è sempre la stessa cosa?

Sono consapevole del fatto che la 'L' sta a lungo e sono anche ben consapevole dell'importanza delle parentesi nelle macro C; Lo sto chiedendo per curiosità.

risposta

84

Se hai scritto

a = 7 INTMAX_MIN; 

che ci si aspetta di ottenere un errore di sintassi, perché a prima vista sarebbe un'espressione illegale. E lo farà, perché si espande a

a = 7 (-9223372036854775807LL); 

che non effettivamente vi darà un errore di sintassi. Ma senza le parentesi che si espanderebbe a:

a = 7 -9223372036854775807LL; 

che non ti dà un errore, pur non essendo, ovviamente, quello che intendeva.

Più in generale, tutte queste definizioni danno espansioni per cose che sembrano identificatori. In un'espressione aritmetica, un identificatore è una "espressione primaria", ma non lo è -9223372036854775807LL. Tuttavia, un'espressione tra parentesi è una "espressione primaria".

E questa è la vera ragione.In modo che la macro espanda che cosa sembra un'espressione primaria a qualcosa che è un'espressione primaria. Non sarai mai sorpreso da ciò che accade. Nella programmazione, la sorpresa di solito è cattiva.

Di solito non importa, ma le persone che hanno scritto i termini non vogliono che funzionino abitualmente. Vogliono che lavorino sempre.

Il LL finale contrassegna questo intero letterale come di tipo long long, che è in genere (e in questo caso è) 64 bit. Senza il suffisso LL, il letterale può essere interpretato come int, long int o long long int, a seconda di quale sia il primo a supportare valori a 64 bit. Inchiodare il tipo può essere importante quanto inchiodare il valore.

+10

Si potrebbe anche discutere di 'a = 7-INT_MAX;' con e senza parentesi attorno a 'INT_MAX', notando che il risultato sarebbe diverso da' a = 7 - INT_MAX; '. –

+0

@JonathanLeffler Come sarebbe il risultato diverso? Non dovresti avere bisogno di parentesi per 'INT_MAX' dato che un intero letterale è un'espressione primaria. –

+3

@EricMSchmidt: _ ... blah, blah ... _ ** ... A meno che ... ** Oh drat! Il processo originale del preprocessore separato tendeva a dare una risposta, ma la versione moderna (come nel 1989 o successiva) tokenizza l'input e l'input rimane tokenizzato, quindi '#define X -7' e' int main (void) {int x = 7-X; ritorno x; } 'produce un programma che esce con lo stato 14. Dovrei averlo ricordato. –

19

È buona norma mettere parentesi su una macro con una costante intera e un operatore unario simili: operatori

#define BLA (-1) 

come unari (- qui) non hanno la più alta precedenza in C. Postfix gli operatori hanno precedenza più alta rispetto agli operatori unari. Ricorda che C non ha costanti negative, ad esempio -1 è un'espressione costante preceduta dall'operatore unario -.

Per inciso PC-Lint suggeriscono parenthesizes in tali macro:

(regola 973): parentheser #define N (-1) operatore unario in macro 'simbolo' non tra parentesi - A unario l'operatore che appare in una macro simile a un'espressione non è stato tra parentesi. Per esempio:

#define N -1 

L'utente può preferire mettere tra parentesi cose come:

#define N (-1) 
13

Questa risposta tenta di mostrare perché è necessario il LL. (Non è facile)
Altre risposte hanno mostrato perché sono necessarie le parentesi.

Calcoliamo tre macro, tutte sono costanti decimali.

#define MAXILL (9223372036854775807LL) 
#define MAXIL (9223372036854775807L) 
#define MAXI (9223372036854775807) 

Anche se MAXI non ha suffisso, che non lo rende tipo int. MAXI avrà il primo tipo in cui si inserisce, sia int, long, long long o un tipo intero esteso.

Anche se MAXIL ha il suffisso L, si avrà il primo tipo si adatti, sia long, long long o un tipo intero esteso.

Anche se MAXILL ha il suffisso LL, si avrà il primo tipo si adatti, sia long long o un tipo intero esteso.

In ogni caso, le macro hanno lo stesso valore, ma potenzialmente diversi tipi.

Vedere C11dr §6.4.4.1 5 per la determinazione del tipo.


Diamo cercare di stamparli e hanno int e long sono a 32-bit e long long e intmax_t sono 64.

printf("I %d %d %d",  MAXI, MAXIL, MAXILL); //Error: type mismatch 
printf("LI %ld %ld %ld", MAXI, MAXIL, MAXILL); //Error: type mismatch 
printf("LLI %lld %lld %lld", MAXI, MAXIL, MAXILL); //Ok 

Tutti e tre nell'ultima riga sono corrette secondo quanto tutte e tre le macro sono long long, il precedente hanno errate corrispondenze di tipo tra l'identificatore di formato e il numero.

Se abbiamo int è a 32 bit e long, long long e intmax_t sono 64, quindi i seguenti sono corrette.

printf("LI %ld %ld", MAXI, MAXIL); 
printf("LLI %lld", MAXILL); 

Il tipo larghezza massima intero ha un identificatore di formato di "%" PRIdMAX. Questa macro non può espandersi a "%ld"e"%lld" per adattarsi a MAXI, MAXIL, MAXILL. È impostato su "%lld" e i numeri relativi a intmax_t devono avere lo stesso tipo.In questo caso, è necessario utilizzare long long e utilizzare solo il modulo MAXILL.


Altre implementazioni possono avere un esteso tipo intero (come int128_t), nel qual caso potrebbe essere utilizzato un suffisso specifico attuazione o qualche meccanismo.

+0

Come nota, con C11 '_Generic' (e prima con la popolare estensione' typeof') i tipi sono diventati più facili da osservare. (In C99 senza estensioni, I non so come si possa osservare la differenza tra 'long' e' long long' se hanno la stessa dimensione e rappresentazione; dato che va bene se l'implementazione fa ipotesi sulla chiamata di convenzioni, e che è abbastanza improbabile che 'long' e' long long' siano passati in modo diverso, la domanda se il suffisso è davvero necessario per i rigidi C99 rimane.) – mafso

Problemi correlati