Existe-t-il un paragraphe de la norme c++ qui dit que l'utilisation de -1
pour cela est portable et la manière correcte ou la seule façon de faire correctement est d'utiliser des valeurs prédéfinies ?
J'ai eu une conversation avec mon collègue, qu'est-ce qui est mieux : utiliser -1
pour un nombre entier non signé maximum ou en utilisant une valeur de limits.h
o std::numeric_limits
?
J'ai dit à mon collègue que l'utilisation de valeurs maximales prédéfinies à partir de limits.h
o std::numeric_limits
est la façon portable et propre de le faire, cependant, le collègue a objecté à l'idée de -1
étant aussi portable que les limites numériques, et plus encore, elle présente un avantage supplémentaire :
unsigned short i = -1; // unsigned short max
peut facilement être changé en n'importe quel autre type, tel que
unsigned long i = -1; // unsigned long max
lors de l'utilisation de la valeur prédéfinie de la limits.h
ou le fichier d'en-tête std::numeric_limits
nécessite également de le réécrire avec le type à gauche.
41 votes
Voir
-
yunsigned
sur la même ligne est garanti pour faire lever quelques sourcils.6 votes
Vous n'avez pas besoin de vous répéter si vous utilisez
auto
.0 votes
@Ron je suis d'accord, mais c'est le hack que mon collègue dit à propos de, comme
-1
sera converti en0 - 1
qui utilisera le débordement et fixera le nombre maximum d'un type.8 votes
J'ai voté pour la réouverture parce que cette question n'est pas une copie exacte de l'original supposé. L'autre question porte sur le comportement de l'arithmétique lorsque les valeurs dépassent la plage d'un type d'entier non signé. Bien que cette question implique cela, elle pose une question différente sur la sémantique de l'utilisation de
-1
.0 votes
Je suppose que le cas réel de votre problème n'est pas dans la question. Mais je parie que le vrai problème était "quelle est la meilleure façon de signaler une erreur lorsqu'une fonction renvoie un entier sans exception". Dans ce cas je répondrai utiliser un booléen pour indiquer l'erreur ! ou nouveau c++17
std::optional
.0 votes
@EricPostpischil C'est l'OP qui ferme en tant que duplicate et la question est "Est-ce que
-1
correct d'utiliser comme valeur maximale d'un entier non signé ?", dans SO deux questions en une est une mauvaise pratique et rend la question trop large.0 votes
Ce pourrait être un meilleur doublon, bien que j'hésite à le marteler : stackoverflow.com/q/2273913/10077
12 votes
Le commentaire de Ron est plus qu'un simple commentaire. Alors que
-1
pourrait être techniquement correct (voir la réponse d'Eric), du point de vue du code propre, ce n'est pas le cas. Déterminer si-1
est une erreur ici vous a pris une question, et Eric une recherche dans la norme.unsigned short i = USHRT_MAX
n'exigerait ni l'un ni l'autre, et serait plus explicite quant à l'objectif visé par la déclaration.0 votes
@Stargateur : Vous pouvez voter pour la fermeture comme trop large si vous le souhaitez, ou suggérer un autre duplicata. Cela ne change rien au fait que la question, telle qu'elle a été formulée (quelle que soit l'intention du PO), n'était pas un doublon de l'original supposé.
5 votes
La question peut s'appliquer à plusieurs langages, mais la réponse n'est pas nécessairement la même pour C et C++. La sélection d'un seul langage réduirait l'étendue inutile de cette question.
0 votes
@chux : -1 ne survivra pas à un changement de type en
auto
. ;-)1 votes
Qu'en est-il de ses systèmes complémentaires ?
0 votes
@ChristianGibbons
some_unsigned_type x = -1;
initialiserax
avec la valeur maximale du type sans tenir compte deint
codage (2's 1's ,SM)1 votes
"
unsigned short i = -1;
peut facilement être changé en n'importe quel autre type" pour obtenir la maximum devrait être réduit : "peut facilement être changé en n'importe quel autre non signé type"0 votes
@chux donc ce n'est pas qu'il prenne l'encodage binaire de ce qu'il faut faire.
-1
aurait été s'il s'agissait d'un type signé ? Intéressant.0 votes
@ChristianGibbons Oui. La conversion entre les types numériques (
int,unsigned,double,bool
etc.) est principalement (voire uniquement) basé sur valeur pas codage .2 votes
Pour mémoire,
auto i = std::numeric_limits<unsigned int>::max();
ne déclare le type qu'une fois exactement. Ainsi, le problème de la facilité d'édition ne s'applique pas au C++, je pense. Commentaire pas réponse puisque cette préoccupation ressemble à un préambule, pas à une question.2 votes
Y a-t-il quelque chose de non-portable à utiliser
~0
à la place ? Dans l'affirmative, l'un est-il conventionnellement préféré à l'autre ?0 votes
"Qu'est-ce qui est mieux : utiliser -1 pour un nombre entier non signé maximum ou utiliser une valeur de limits.h ou std::numeric_limits" --> La considération de ce qui est mieux (meilleur) aurait dû être ouverte à d'autres solutions aussi. Il y a 3 types de personnes : ceux qui pensent toujours en binaire et ceux qui ne le font pas.
1 votes
Hmm, juste par curiosité, j'ai cherché dans l'arbre des sources de Linux 4.15-rc1 pour cela. J'ai vu 112 affectations de
-1
en quelque chose de non signé, 69 affectations deU.*_MAX
à quelque chose de non signé, et 92 affectations de~0
à une chose non signée.1 votes
@ChristianGibbons Le problème avec
~0
est qu'il n'est pas garanti qu'il soit égal à-1
dans toutes les représentations.0 votes
@DKrueger Ce n'est pas -1 que nous voulons en fin de compte. Ce que nous recherchons est la valeur maximale d'un type non signé.
3 votes
@ChristianGibbons Attribution
-1
à une variable non signée fait que la variable contient la valeur maximale car, en raison de l'arithmétique modulo, vous assignez effectivement(UINT_MAX + 1) + (-1)
. Considérons maintenant une représentation en signe et magnitude où~0
serait égal àINT_MIN
. Lorsqu'elle est affectée à un int non signé, la valeur est en fait la suivante(UINT_MAX + 1) + INT_MIN
qui n'est pas égal àUINT_MAX
.0 votes
@DKrueger Oh, je vois. Puisque ce n'était pas spécifié autrement, le littéral est traité comme un nombre signé plutôt que non signé. Donc pour résoudre ce problème, il faudrait faire
~0U
pour éviter de traiter la conversion de signé à non signé ?3 votes
@ChristianGibbons
~0U
fonctionnera tant que le type de la variable n'est pas plus large qu'un entier non signé.1 votes
@ChristianGibbons Je recommande fortement que, si vous n'avez pas l'intention d'utiliser les constantes définies dans la section
limits.h
ou le C++std::numeric_limits
à juste-1
au lieu de~0U
. Pour être clair, les deux sont peu intuitifs et nécessitent des connaissances de bas niveau pour être compris et un raisonnement minutieux pour prouver qu'ils sont corrects. Cependant, la conversion d'une valeur négative en un type non signé est définie de manière triviale dans toutes les normes C en termes de leur valeurs Mais les opérateurs binaires (autres que les décalages) sont définis (à la fois conceptuellement et dans la norme) strictement en termes de représentation binaire réelle des données.2 votes
@ChristianGibbons Aussi, je pense que la gymnastique mentale nécessaire pour vraiment prouver correctement
~0U
est correct lorsque vous le voyez dans le code sont plus complexes que celles requises pour prouver que-1
est correcte. Et je suis inquiet pour tout le monde, sauf pour les quelques personnes qui comprennent et intériorisent suffisamment les normes C pour faire cette gymnastique mentale correctement,~0U
est légèrement plus susceptible d'induire en erreur et de produire un malentendu sur les détails de pourquoi cette construction fonctionne que-1
(et ces subtiles incompréhensions se répercutent sur d'autres codes subtilement incorrects).0 votes
Le fichier d'en-tête :
limits.h
contient la définition deUINT_MAX
ce qui est ce que vous recherchez.0 votes
Je pense qu'il est utile de préciser qu'en C, on ne peut pas toujours connaître le type, donc on n'a pas de macro. Par exemple avec size_t en C89 où il n'y a pas de SIZE_MAX.
0 votes
Duplicata de cette question mais aussi celui-ci y celui-ci .
0 votes
@pipe : C89 n'est pas le C standard. Le tag C implique le C standard, qui fournit ces macros depuis 18 ans. Et en C le type d'un objet est toujours connu pour toute expression, donc on peut très bien l'utiliser. N'écrivez pas de code pour les anciennes versions si vous n'en avez pas besoin !
0 votes
@Olaf C ne dispose pas d'un moyen d'interroger le type sous-jacent pour les types provenant de
typedef
. Et en tant que développeur embarqué, oui. J'en ai souvent besoin.0 votes
@pipe : Le type d'un objet est clairement déterminé par l'expression. Et si vous avez besoin du type du LHS d'une affectation, utilisez simplement le type de cet objet. Pendant les >20 ans de développement embarqué en C (et avant cela sur d'autres systèmes), je n'ai pas eu de problème avec cela. Si c'était le cas, vous devriez peut-être remettre en question votre approche. Cela dit, il existe une macro pour chaque type standard et ses alias. (En passant, le C ne permet pas de définir de nouveaux types scalaires et de nouveaux alias.
typedef
ne définit jamais un nouveau type - c'est une différence avec C++).0 votes
@VictorPolevoy - merci de modifier cette question et de la rendre C++ -seulement, supprimez le C étiquette. Sinon, la question sera supprimée en tant que doublon.
0 votes
@RustyX ok, mais pour les réponses ?
0 votes
@RustyX fait. J'ai voté pour la réouverture.
0 votes
La norme elle-même utilise -1 comme valeur de la variable non signée
std::basic_string::npos
.0 votes
@interjay Cool chose à savoir, merci. En disant "standard", vous voulez dire l'implémentation gcc libstdc++ ?
0 votes
Je voulais dire la norme C++ elle-même, voir la définition de
npos
sur 24.3.2p5 .