1
votes

Comparaison C 'x <0' où le type de 'x' est arbitraire, c'est-à-dire peut être non signé

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.


6 commentaires

En parallèle avec INT_MIN implémentez THEVALUET_MIN et utilisez if ((THEVALUET_MIN <0) && (x <0)) / * ... * /;


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éfinissez TheValueT .


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 plaint


Je ne reçois pas d'avertissement de toute façon mais est-ce que if (TheValueT vous donne un avertissement?


3 Réponses :


1
votes

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;
}


3 commentaires

@ 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é.



2
votes

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.


4 commentaires

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".



1
votes

Variante sur un thème . Fonctionne aussi pour FP.

if (x <= 0 && x != 0) {


1 commentaires

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.