Est entier non signé de la soustraction comportement défini?
J'ai trouver le code de quelqu'un qui semble croire qu'il y est un problème de soustraction d'un entier non signé à partir d'un autre nombre entier de même type, alors que le résultat serait négatif. De sorte que le code comme ce serait incorrect, même si elle arrive à travailler sur la plupart des architectures.
unsigned int To, Tf;
To = getcounter();
while (1) {
Tf = getcounter();
if ((Tf-To) >= TIME_LIMIT) {
break;
}
}
C'est la seule vaguement pertinents citation du C standard, j'ai pu trouver.
Un calcul impliquant non signé opérandes ne peut jamais déborder, car un
résultat qui ne peut pas être représenté par la entier non signé
le type est réduit modulo le nombre qui est plus grand que le plus grand
valeur qui peut être représentée par le type résultant.
Je suppose que l'on pourrait prendre cette citation à dire que lorsque l'opérande de droite est plus grande que l'opération est ajusté pour être significatif dans le contexte de modulo tronquée numéros.
c'est à dire
0x0000 - 0x0001 == 0x 1 0000 - 0x0001 == 0xFFFF
par opposition à l'aide de la mise en œuvre dépend signé sémantique:
0x0000 - 0x0001 == (unsigned)(0 + -1) == (0xFFFF mais aussi 0xFFFE ou 0x8001)
Qui ou quoi l'interprétation est la bonne? Se définit-elle à tous?
- Le choix des mots dans la norme est regrettable. Qu'il “ne peut jamais dépassement” signifie qu'elle n'est pas une situation d'erreur. En utilisant la terminologie de la norme, au lieu de faire déborder la valeur de “l'enveloppe.”
Vous devez vous connecter pour publier un commentaire.
Le résultat d'une soustraction de la génération d'un nombre négatif dans un type non signé est bien définie:
Comme vous pouvez le voir,
(unsigned)0 - (unsigned)1
est égal à -1 modulo UINT_MAX+1, ou, en d'autres termes, UINT_MAX.Note que, bien qu'il ne dit "Un calcul impliquant non signé opérandes peuvent jamais de débordement", qui pourraient vous amener à croire qu'il s'applique uniquement pour le dépassement de la limite supérieure, c'est présenté comme un motivation pour la liaison de la partie de la phrase: "un résultat qui ne peut pas être représenté par la résultante de type entier non signé est
réduit modulo le nombre qui est plus grand que la plus grande valeur qui peut être
représenté par le type résultant." Cette expression n'est pas limitée à de dépassement de la limite supérieure de la nature, et s'applique également à des valeurs trop faibles pour être représenté.
uint
a toujours été destiné à représenter la mathématique anneau les entiers0
parUINT_MAX
, avec les opérations d'addition et de multiplication moduloUINT_MAX+1
, et pas à cause d'un dépassement de capacité. Toutefois, elle permet de poser la question de savoir pourquoi, si les anneaux sont un type de données fondamental, la langue n'offre pas plus de soutien général pour les anneaux de tailles.Lorsque vous travaillez avec des unsigned types, l'arithmétique modulaire (aussi connu comme "envelopper" comportement) est mis en place. Pour comprendre cette l'arithmétique modulaire, il suffit de jeter un coup d'oeil à ces horloges:
9 + 4 = 1 (13 mod 12), donc à l'autre direction, il est: 1 - 4 = 9 (-3 mod 12). Le même principe est appliqué tout en travaillant avec des types non signés. Si le type de résultat est
unsigned
, puis l'arithmétique modulaire prend place.Maintenant, regardez les opérations suivantes stocker le résultat dans un
unsigned int
:Lorsque vous voulez vous assurer que le résultat est
signed
, puis stockées danssigned
variable ou de le jeter auxsigned
. Lorsque vous voulez obtenir la différence entre les nombres et assurez-vous que l'arithmétique modulaire ne sera pas appliquée, alors vous devriez envisager d'utiliserabs()
fonction définie dansstdlib.h
:Être très prudent, surtout lors de l'écriture de conditions, en raison de:
mais
int d = abs(five - seven);
n'est pas bon. Premièrefive - seven
est calculée: promotion des feuilles de l'opérande types deunsigned int
, le résultat est calculé modulo(UINT_MAX+1)
, et donneUINT_MAX-1
. Cette valeur est le paramètre réel àabs
, qui sont de mauvaises nouvelles.abs(int)
provoque un comportement indéfini en passant l'argument, car il n'est pas dans la gamme, etabs(long long)
pouvez probablement contenir la valeur, mais un comportement indéfini se produit lorsque la valeur de retour est contrainte àint
pour initialiserd
.int c = five - seven;
est mauvais plus immédiatement et pour la même raison.abs()
etint c =
attendre signé de type, de sorte que la conversion implicite doit s'assurer que ce que vous avez décrit ne devrait pas arriver, n'est-ce pas?operator T()
. L'ajout dans les deux expressions dont nous sommes saisis est effectuée dans le typeunsigned int
, basé sur l'opérande types. Le résultat de l'addition estunsigned int
. Alors que le résultat est implicitement convertie dans le type requis dans le contexte, une conversion qui échoue parce que la valeur n'est pas représentable dans le type nouveau.double x = 2/3;
vsdouble y = 2.0/3;
abs()
que vous suggérez ici, ce qui (si je suis en train de lire correctement) réinterprète une valeur non signée signée, et prend sa valeur absolue, semble susceptible d'être fragile et non portable. Je suis un peu surpris de voir cela écrit avec tant de désinvolture sans avertissement.Bien, la première interprétation est la bonne. Cependant, votre raisonnement sur les "signé de la sémantique" dans ce contexte est mauvais.
Encore une fois, votre première interprétation est correcte. Non signé de l'arithmétique de suivre les règles de l'arithmétique modulo, ce qui signifie que
0x0000 - 0x0001
évalue à0xFFFF
pour non signé de 32 bits types.Cependant, la deuxième interprétation (l'un basé sur la "signé" sémantique) est également nécessaire pour produire le même résultat. I. e. même si vous évaluez
0 - 1
dans le domaine de type signé et obtenir-1
comme le résultat intermédiaire, ce-1
est toujours nécessaire pour produire0xFFFF
quand plus tard il est converti en type non signé. Même si certains plate-forme utilise un exotique représentation des entiers signés (1 complément, signé de l'ampleur), cette plate-forme est toujours nécessaire d'appliquer des règles de l'arithmétique modulo lors de la conversion d'entier signé de valeurs non signées ceux.Par exemple, cette évaluation
est toujours garanti pour produire
UINT_MAX
dansc
, même si la plate-forme est à l'aide d'un exotique représentation des entiers signés.Avec unsigned numéros de type
unsigned int
ou plus, en l'absence de conversions de type,a-b
est définie comme ce qui donne le nombre non signé qui, lorsqu'il est ajouté àb
, donneraa
. Conversion d'un nombre négatif non signé est définie comme ce qui donne le nombre qui, ajouté à la le signe inversé nombre d'origine, aura un rendement de zéro (donc la conversion de -5 à unsigned donnera une valeur ajoutée à 5, aura un rendement de zéro).Noter que unsigned des nombres plus petits que
unsigned int
peut obtenir une promotion de typeint
avant la soustraction, le comportement dea-b
dépendra de la taille deint
.