Existe-t-il un moyen portable de définir INT_MAX?

J’ai trouvé les définitions suivantes dans /usr/include/limits.h:

# define INT_MIN (-INT_MAX - 1)

# define INT_MAX 2147483647

En outre, il semble que tous les XXX_MAX de ce fichier d’en-tête soient explicitement définis à partir d’une constante numérique.

Je me demande s’il existe un moyen portable (en fonction de la taille des mots sur différentes plates-formes) de définir un INT_MAX?

J’ai essayé ce qui suit:

~((int)-1)

Mais cela semble incorrect.

Une courte explication est également très appréciée.

Pour INT_MAX dans l’en-tête standard limits.h , l’implémenteur est lié par le fait qu’il doit être utilisable dans les directives du préprocesseur #if . Cela exclut tout ce qui concerne la sizeof ou les jets.

Si vous voulez juste une version qui fonctionne dans les expressions C réelles, ceci fonctionnera peut-être:

 (int)-1U/2 == (int)(-1U/2) ? (int)-1U : (int)(-1U/2) 

Le concept ici est que int peut avoir le même nombre de bits de valeur que unsigned , ou un bit de valeur de moins; la norme C permet soit. Afin de vérifier lequel il est, vérifiez le résultat de la conversion (int)-1U . Si -1U correspond à int , sa valeur ne doit pas être modifiée par la conversion, ainsi l’égalité sera vraie. Si -1U ne convient pas à int , la -1U entraîne un résultat de type int défini par l’implémentation. Quelle que soit la valeur, l’égalité sera fausse simplement par la plage de valeurs possibles.

Notez que, techniquement, la conversion en int peut générer un signal défini par l’implémentation, plutôt qu’une valeur définie pour l’implémentation, mais cela ne se produira pas si vous utilisez une expression constante qui sera évaluée. au moment de la compilation.

J’aime les définitions:

 #define INT_MIN (1 << (sizeof(int)*CHAR_BIT-1)) #define INT_MAX (-(INT_MIN+1)) 

Non, car il n’existe aucun moyen portable de connaître la différence de nombre de bits de valeur entre int et unsigned .

Il existe un moyen portable d’obtenir UINT_MAX , à savoir -1u car les entiers non signés sont des types modulo. Par conséquent, l’expression de INT_MAX est

 (int)(UINT_MAX >> (value_bits - value_bits)) 

Malheureusement, il n’existe aucun moyen d’obtenir value_bits - value_bits .

En C ++, cela semble être possible grâce à la méta-programmation de modèles, à partir de 15 bits. (La plage [-32767, 32767] est garantie pour pouvoir être représentée en int .)

 template struct max0 { static const int value = max0::value * 2 + 1; }; template<> struct max0<15> { static const int value = 32767; }; template struct max1 { static const int value = max0::value > max0::value ? max1::value : max0::value; }; #define INT_MAX (max1<15>::value) 

Mais je trouve cela excessif et je m’en __INT_MAX__ ; (défini par le compilateur __INT_MAX__ .

EDIT: Oups!

 max.cpp: In instantiation of 'const int max0<32>::value': max.cpp:17:51: recursively required from 'const int max1<16>::value' max.cpp:17:51: required from 'const int max1<15>::value' max.cpp:28:28: required from here max.cpp:4:52: warning: integer overflow in expression [-Woverflow] static const int value = max0::value * 2 + 1; ~~~~~~~~~~~~~~~~~~~~~~^~~ max.cpp:4:22: error: overflow in constant expression [-fpermissive] static const int value = max0::value * 2 + 1; ^~~~~ max.cpp:4:22: error: overflow in constant expression [-fpermissive] max.cpp:4:22: error: overflow in constant expression [-fpermissive] max.cpp: In instantiation of 'const int max0<914>::value': max.cpp:17:51: recursively required from 'const int max1<16>::value' max.cpp:17:51: required from 'const int max1<15>::value' max.cpp:28:28: required from here max.cpp:4:52: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) static const int value = max0::value * 2 + 1; ~~~~~~~~~~~~~~~~~~~~~~^~~ compilation terminated. 

Si nous supposons la notation complémentaire de 1 ou 2 et 8 bit / octet et pas de remplissage:

 #define INT_MAX ((1 << (sizeof(int)*8 - 2)) - 1 + (1 << (sizeof(int)*8 - 2))) 

Je ne vois pas de débordement dans les changements ni dans les ajouts. Je ne vois pas non plus UB. Je suppose que l'on pourrait utiliser CHAR_BIT au lieu de 8.

Dans les compléments 1 et 2, le maximum d'int serait power(2,(sizeof(int)*Bits_per_byte - 1) - 1 Au lieu de pouvoir, nous utiliserons le décalage, mais nous ne pouvons pas trop en changer en même temps. forme power(2,(sizeof(int)*Bits_per_byte - 1) en faisant la moitié deux fois. Mais le débordement est un non-non, donc soustrayez 1 avant d’append la 2ème moitié plutôt que la fin. () mettre l'accent sur l'ordre d'évaluation.

Comme l'a souligné @caf, cette méthode échoue s'il y a des bits de remplissage - inhabituels mais possibles.

L'informatique INT_MIN est un peu plus délicate à faire fonctionner en complément de 2 et 1, mais une approche similaire fonctionnerait, mais c'est une autre question.

Eh bien, on peut essayer

 #define INT_MAX (int) ((unsigned) -1 / 2) 

qui “devrait” fonctionner sur des plates-formes avec une taille de mot différente et même avec différentes représentations de valeurs entières signées. (unsigned) -1 générera de manière UINT_MAX valeur UINT_MAX , qui correspond au modèle tout-bits-un. Divisé par 2, il devrait devenir la valeur maximale attendue pour le type entier signé, qui dépense le bit pour représenter le signe.

Mais pourquoi? Les fichiers d’en-tête standard et leurs définitions ne sont pas supposés être portables.

En passant, la définition de INT_MIN vous avez citée ci-dessus n’est pas portable. Il est spécifique à la représentation en complément à 2 des entiers signés.