dépassement de capacité arithmétique parce signé caractères dans un programme C
Nous savons que signed char
peuvent avoir des valeurs uniquement à partir de -128
à 127
.
mais quand on lance le programme ci-dessous aucun débordement se produit même si le l de sortie dépasse la plage de signé personnage.
#include <stdio.h>
int main()
{
char i = 60;
char j = 30;
char k = 10;
char l = (i*j)/k;
printf("%d ", l);
return 0;
}
la sortie de
l
est180
qui est hors de portée pourchar l
, mais je n'obtiens pas d'erreur.
dans l'autre scénario, si nous prenons le même programme, mais au lieu de la fonction arithmétique si nous avons simplement mis l=180
et essayez d'imprimer alors nous obtenons une réponse incorrecte.
#include <stdio.h>
int main()
{
char i = 60;
char j = 30;
char k = 10;
char l = 180;
printf("%d ", l);
return 0;
}
la réponse que je reçois dans le 2ème cas est -76
.
quelqu'un peut-il expliquer pourquoi? même si je suis pratiquement l'exécution de la même chose, mais j'obtiens des résultats différents.
EDIT:
C'est l'exemple classique que les calculs intermédiaires sont réalisés dans int
et pas char
donc en 1er quand je fais le calcul, il prend toutes les valeurs de type int et dans la partie plus tard, je suis en mentionnant explicitement comme char.
- Peut-être que votre compilateur est cassé ? Quel compilateur utilisez-vous ?
- Le premier extrait n'est pas reproductible: ideone.com/B4b4AJ
- Je dirais que c'est de l'optimisation. L'expression est juste évaluée comme
int
droit à l'instruction print. Ou vous n'êtes pas de dire la vérité. - Pourquoi l'optimiseur de permis de rompre la troncature de char ?
- pas de mon compilateur n'est pas cassé , j'ai testé le programme ci-dessus sur les deux ide dire DEVC++ et VS2015 , même vous, vous pouvez essayer de le au-dessus de deux versions d'un même programme et que pouvez-vous voir que les réponses sont différentes, en dépit qu'ils en disent la même logique.
- Pas sûr que c'est permis.. c'est plutôt la deuxième partie du commentaire.
- Eugène Sh , monsieur, vous pouvez vous-même vérifier en cours d'exécution sur l'un de vos IDE , j'obtiens des résultats différents à partir du programme.
- reproduit sur SuSE linux sur IBAN zSeries gcc (SUSE Linux) 4.3.4, niveau d'optimisation -O3
- Fait-il preuve de la même sans l'optimisation?
- Je vais essayer ......
- Sur gcc 4.8.4 je ne peux que reproduire alors que j'ai spécifié unsigned char.
- C'est de 180 même avec -O0 sur IBM Z
- Débordement d'entier UB. Votre compilateur optimiseur utilise pour éliminer l'variable complètement. Vite toujours les atouts précise. Ne fonctionne pas dans le 2ème cas, puisque le compilateur a déjà généré -76.
- Il n'y a pas de dépassement de capacité dans le calcul lui-même, que dans la conversion de
char
. Et la conversion d'une valeur qui ne rentre pas dans un plus petit nombre entier signé est de type définis par l'implémentation, pas de UB. - Mais la mise en œuvre définies par le comportement ne peut pas expliquer le comportement décrit, comme il n'est pas sur le casting seulement ici..
- Il s'avère être une question intéressante.
- Je n'ai pas d'offrir une explication (je ne vois pas d'autre explication qu'un compilateur bug ou une erreur de la part de l'OP), j'ai seulement dit que ce n'est pas AC.
- stackoverflow.com/questions/18195715/... indique qu'il est AC si, comme le résultat du calcul est un nombre entier signé.
- Mais où est le débordement ici?
- Le résultat devrait être le même. C'est un compilateur (optimisation) bug.
- Maintenant, je pense que le problème est du au fait que
printf
sva_arg
n'ont pas en réalité aucune information de type, de sorte que l'entier de la promotion, nous attendons de ne pas réellement se produire, rendant soit AC ou indéterminée. Pas un bug. La différence est dans le contenu de la mémoire d'étendrel
- le débordement est essayer de s'adapter à 180 dans un (présumé) signed char. Ce qui ferait UB et donc les résultats ne doivent pas être les mêmes. va_arg en fait de promouvoir des types d'entiers plus petits que les int int.
- Exactement. C'est le problème ici. Il s'attend à ce
int
pour%d
, c'est l'ensemble de laint
de la mémoire à la place dechar
. - Lire le fil. Elle est définie par l'implémentation.
- oh ? stackoverflow.com/questions/23983471/... stackoverflow.com/questions/22844360/...
- En fait, j'ai mal dits. Var-les arguments de la fonction effectue l'argument par défaut promotions incluent entier promotions.
- Hm. Dans ce cas, je ne peux pas venir avec quelque chose, mais un bug..
- Je viens de découvrir votre commentaire indiquant que la conversion de 180, ce qui est un int en char signé UB. Ce n'est pas parce C11 6.3.1.3.p3 membres elle est définie par l'implémentation.
- Le propriétaire a accepté la réponse qui a déclaré que la réclamation était faux, dans le temps de le dire..
- Une autre preuve que quelque chose commençant par "Nous savons que ..." ou une expression similaire est mauvais >95% des fois. si
char
est signé est dépendant de l'implémentation. Etsigned char
a un **distance minimale de-127..127
. peut être beaucoup plus grande, si. - Je verrais plutôt explicite de commentaire à ce sujet. Voir aussi Ingo Leonhardts commentaires ci-dessus.
- Veuillez indiquer votre plate-forme cible (PROCESSEUR, système d'exploitation, compilateur de détails)
Vous devez vous connecter pour publier un commentaire.
Êtes-vous sûr que vous avez fait et tester ce que vous avez décrit dans le premier extrait?
Si il est exécuté, il
débordementss'enroule autour comme prévu.Cela fait une grande différence si vous n'avez
Et si vous n'avez
Comme dans le deuxième cas, le compilateur pourrait en déduire que l'utilisation d'un
int
comme sortie, (le résultat ne pouvait pas s'adapter à l'intérieur d'un char sans emballage autour évidemment), et surtout parce que les calculs intermédiaires sont réalisés dansint
et paschar
.En outre, considérer que le résultat correspond en fait à l'intérieur d'un
unsigned char
, afin de vérifier ce cas.Dans votre cas, je voudrais commencer à penser à des cas d'un problème de compilateur aussi, mais seulement après que je suis sûr de ce que le programme exécuté devrait le faire.
Le langage C est en fait incapable d'exercer toute forme de calculs sur
char
types.char
est un petit entier de type, ce qui signifie que chaque fois qu'il apparaît dans le cadre d'une expression, elle obtient toujours implicitement promuint
. Ceci est appelé entier de promotion de la ou l'entier règles de la promotion.En outre, il existe un autre type implicites de conversion vers
char
, puisque vous stockez le résultat, qui est de typeint
, à l'intérieur d'unchar
. Ceci est appelé lvalue de conversion: il convertit le résultat d'une expression du type de l'objet désigné.est donc tout à fait équivalent à
Depuis tout calcul est effectué sur le type de
int
, il n'y a pas de débordement. Le résultat 180 peut ou ne peut pas répondre à l'intérieur d'unchar
.Vous devriez éviter d'utiliser des
char
de toute forme de l'arithmétique, parce qu'il a mise en œuvre définie par ce paramètre. Sur un système, il pourrait être signée, -128 à 127, sur un autre système, il pourrait ne pas être signé, de 0 à 255. Utilisationuint8_t
au lieu de cela, il est une meilleure et plus sûre type.180
ne rentre pas dans la Fpochar
.unsigned char
où une arithmétique résultat est stocké. Qui garantit la même ou une plus grande gamme deuint8_t
.Cela se produit parce que les intermédiaires sont les calculs de l'int, pas avec char. char peut être signé ou non signé, mais les spécifications disent eux-mêmes char, signed char et unsigned char sont de 3 types distincts.
EDIT: Trouvé pourquoi cela se produit: signed char débordements, ce qui déclenche comportement indéfini. C'est pourquoi vous n'obtenez pas une constante. Signé types intégraux (char signé, signé int, signé de long) déclencher un comportement indéfini de débordement. L'optimisation est autorisé à faire quoi que ce soit, bien qu'il se compose essentiellement d'ignorer l'existence de la zone de débordement.
int
, mais la cession dechar l
forcer une conversion àchar
. La valeur réelle écrite est mise en œuvre défini mais je ne vois pas comment il pourrait en être de 180 (en supposant signéchar
).int
peut contenir le produit, mais ça n'aide pas si vous puis de le convertir enchar
comme cela est fait ici. Et le deuxième exemple montre quechar
est signé à l'OP de la machine.char
n'est pas nécessaire de disposer de 8 bits. L'OP ne fait pas mention de la plate-forme cible.