GIVEN:
Un type défini comme TheValueT
qui peut être configuré arbitrairement, par exemple comme uint8_t
ou int64_
. Soyons un peu de code:
TheValueT x = ...; ... do something to 'x' ... if( x < 0 ) { /* Do something. */ }
Il arrive que si TheValueT
est défini comme un type non signé, le compilateur se plaint de «condition toujours vraie en raison de la plage limitée de type ...».
QUESTION:↑
Comment peut-on éviter l'avertissement du compilateur tout en laissant TheValueT
être toujours de type entier arbitraire? La solution doit être applicable à la plus large gamme de compilateurs C.
3 Réponses :
Peut-être une solution générique ?
sh i ll
Aucune condition toujours vraie en raison d'un avertissement de type limité .
Sortie
#include <stdio.h> #include <stdlib.h> #define less_than_zero(x) _Generic((x) + 0, \ int: (x) < 0, \ long: (x) < 0, \ long long: (x) < 0, \ default: (x) * 0 \ ) #if 1 int main(void) { short sh = -1; int i = -1; long long ll = -1; unsigned short us = -1u; unsigned u = -1u; unsigned long long ull = -1u; if (less_than_zero(sh)) puts("sh"); if (less_than_zero(i)) puts("i"); if (less_than_zero(ll)) puts("ll"); if (less_than_zero(us)) puts("us"); if (less_than_zero(u)) puts("u"); if (less_than_zero(ull)) puts("ull"); return 0; }
@ Frank-ReneSchäfer Si une restriction du compilateur existe, cela devrait faire partie de la question.
Correct, j'ajouterai la note.
Je l'aime bien, mais il ne prend pas en charge TheTypeT
étant un type d'extension signé.
Un moyen simple et sûr d'écrire votre test serait le suivant:
TheValueT x = /* ... */; if (x < 1 && x != 0) { // do something }
Il est possible qu'un compilateur assez intelligent vous avertisse de toute façon, mais il en va de même pour toute alternative correcte qui peut être écrit pour couvrir tous les types d'entiers possibles (y compris les types d'extension). Cela permet de contourner l'avertissement dans mon implémentation.
Aucune alternative nécessitant un calcul arithmétique impliquant la valeur de x
ne produit de manière définie le résultat correct dans tous les cas - ceux-ci rencontrent des problèmes avec les valeurs de x
aux extrêmes de ses plages ou d'autres types.
Cela suppose que TheTypeT
doit être un Type entier . Si les types flottants sont également une possibilité, alors votre meilleur pari peut être de simplement vivre avec l'avertissement, ou d'utiliser un indicateur de compilateur pour désactiver cet avertissement pendant les versions de production.
C'est de loin la solution la plus élégante et la plus complète!
Puisque x
peut être "configuré arbitrairement", que se passe-t-il si x
est un double
et a la valeur 0.25
? Il passerait votre test ( x <1 && x! = 0
) et traiterait 0.25
comme s'il s'agissait d'une valeur négative.
Oui, @abelenky. J'aborde ce problème dans le dernier paragraphe de la réponse: la solution proposée ne traite explicitement que des types entiers.
Ma réponse traite également les types à virgule flottante. Il n'est pas nécessaire de simplement "vivre avec l'avertissement".
Variante sur un thème . Fonctionne aussi pour FP.
if (x <= 0 && x != 0) {
Certes, cela a du charme. Je pourrais imaginer, cependant, que la réduction de valeur constante de certains compilateurs pourrait être en mesure de comprendre cela. La solution de John avec le 'x <1' contient une opération '-1'. Étant donné que pour les types non signés, le résultat est quelque chose de vide, une réduction constante peut être empêchée.
En parallèle avec
INT_MIN
implémentezTHEVALUET_MIN
et utilisezif ((THEVALUET_MIN <0) && (x <0)) / * ... * /; code >
stackoverflow.com/questions/6259224 n'est pas exactement la même chose, mais peut vous donner quelques idées.
@rtoijala: Ce n'est pas le cas.
Vous pouvez essayer de conditionner le code afin qu'il soit supprimé lorsque vous utilisez un type non signé pour
TheValueT
, bien que cela impliquerait d'ajouter une définition de macro à l'endroit où vous définissezTheValueT
.Détail "Il arrive que si TheValueT est défini comme un type non signé" et que le type est / aussi étroit que
int
... le compilateur se plaintJe ne reçois pas d'avertissement de toute façon mais est-ce que
if (TheValueT vous donne un avertissement?