Tant de parenthèses dans les en-têtes standard gcc

Pourquoi les expressions constantes dans les fichiers d’en-tête GCC sont-elles entourées de parenthèses, comme ceci?

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

Quelle serait la différence si je omettais les parenthèses, de cette façon?

 #define INTMAX_MIN -9223372036854775807LL #define INTMAX_MAX 9223372036854775807LL 

Et pourquoi y a-t-il le suffixe “L”? Serait-ce le même si j’écris ce qui suit?

 #define INTMAX_MIN -9223372036854775807 #define INTMAX_MAX 9223372036854775807 

Y a-t-il une utilité réelle ou est-ce toujours la même chose?

Je sais que le «L» est long et je suis également conscient de l’importance des parenthèses dans les macros C; Je demande cela par curiosité.

Si vous avez écrit

 a = 7 INTMAX_MIN; 

vous vous attendriez à recevoir une erreur de syntaxe, car à première vue, ce serait une expression illégale. Et ce sera le cas, car il s’étend à

 a = 7 (-9223372036854775807LL); 

ce qui vous donne effectivement une erreur de syntaxe. Mais sans les parenthèses, il serait élargi à:

 a = 7 -9223372036854775807LL; 

ce qui ne vous donne pas d’erreur, même si ce n’est évidemment pas ce que vous vouliez.

Plus généralement, toutes ces définitions donnent des extensions pour des choses qui ressemblent à des identificateurs. Dans une expression arithmétique, un identifiant est une “expression primaire”, mais non -9223372036854775807LL. Cependant, une expression entre parenthèses est une “expression primaire”.

Et c’est la vraie raison. Alors que la macro développe ce qui ressemble à une expression primaire à quelque chose qui est une expression primaire. Vous ne serez jamais surpris par ce qui se passe. En programmation, la surprise est généralement mauvaise.

Habituellement, cela n’a pas d’importance, mais les personnes qui ont écrit les définitions ne veulent pas qu’elles travaillent habituellement. Ils veulent qu’ils travaillent toujours.

Le LL final marque ce littéral entier comme de type long long , qui est généralement (et dans ce cas est) 64 bits. Sans le suffixe LL, le littéral pourrait être interprété comme étant int, long int ou long long int, selon la première des valeurs sockets en charge par les valeurs 64 bits. Trouver le type peut être aussi important que de réduire la valeur.

Il est conseillé de placer des parenthèses sur une macro avec une constante entière et un opérateur unaire comme ceci:

 #define BLA (-1) 

comme les opérateurs unaires ( - ici) n’ont pas la plus haute priorité dans C. Les opérateurs Postfix ont une priorité plus élevée que les opérateurs unaires. Rappelez-vous que C n’a pas de constantes négatives, par exemple -1 est une expression constante précédée de l’opérateur - unary.

En outre, PC-Lint suggère entre parenthèses de telles macros:

(règle 973): parenthèse #define N (-1) Opérateur unaire dans la macro ‘Symbol’ non entre parenthèses – Un opérateur unaire apparaissant dans une macro de type expression s’est avéré ne pas être mis entre parenthèses. Par exemple:

 #define N -1 

L’utilisateur peut préférer mettre entre parenthèses des éléments tels que:

 #define N (-1) 

Cette réponse tente de montrer pourquoi le LL est nécessaire. (Ce n’est pas facile.)
D’autres réponses ont montré pourquoi les parenthèses sont nécessaires.

Codons trois macros, toutes sont des constantes décimales .

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

Même si MAXI n’a pas de suffixe, cela ne le fait pas taper int . MAXI aura le premier type dans lequel il s’intègre, soit int , long , long long ou un type entier étendu.

Même si MAXIL a le suffixe L , il aura le premier type dans MAXIL il s’inscrit, qu’il soit long , long long ou entier.

Même si MAXILL a le suffixe LL , il aura le premier type dans MAXILL il s’inscrit, qu’il soit long long ou long long .

Dans tous les cas, les macros ont la même valeur, mais des types potentiellement différents.

Voir C11dr §6.4.4.1 5 pour la détermination du type.


Essayons de les imprimer et int et long sont 32-bit et long long et intmax_t sont 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 

Tous les trois dans la dernière ligne sont corrects car les trois macros sont long long , les précédentes ont des erreurs de correspondance entre le spécificateur de format et le nombre.

Si on a int est 32-bit et long , long long et intmax_t sont 64, alors ce qui suit est correct.

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

Le type entier de largeur maximale a un spécificateur de format de "%" PRIdMAX . Cette macro ne peut pas s’étendre à "%ld" et "%lld" pour accepter MAXI, MAXIL, MAXILL . Il est défini sur "%lld" et les nombres liés à intmax_t doivent avoir le même type. Dans ce cas, long long et seule la forme MAXILL doit être utilisée.


D’autres implémentations pourraient avoir un type entier étendu (comme int128_t ), auquel cas un suffixe spécifique à l’implémentation ou un mécanisme pourrait être utilisé.