La conversion de Type - non signé signé int/char
J'ai essayé d'exécuter le programme ci-dessous:
#include <stdio.h>
int main() {
signed char a = -5;
unsigned char b = -5;
int c = -5;
unsigned int d = -5;
if (a == b)
printf("\r\n char is SAME!!!");
else
printf("\r\n char is DIFF!!!");
if (c == d)
printf("\r\n int is SAME!!!");
else
printf("\r\n int is DIFF!!!");
return 0;
}
Pour ce programme, j'obtiens le résultat suivant:
char est DIFF!!!
int est la MÊME!!!
Pourquoi faisons-nous les différentes sorties pour les deux?
Si la sortie sera comme ci-dessous ?
char est le MÊME!!!
int est la MÊME!!!
Un codepad lien.
- Implicite de type entier de promotion de la frappe encore!
- Explication détaillée ici.
Vous devez vous connecter pour publier un commentaire.
C'est en raison des différents types implicites des règles de conversion en C. Il y en a deux qu'un programmeur en C doit savoir: l'habitude de l'arithmétique des conversions et la entier promotions (la dernière partie de l'ancien).
Dans le char le cas où vous avez les types
(signed char) == (unsigned char)
. Ce sont les deux petit entier types. Autres petites types d'entiers sontbool
etshort
. Le entier règles de la promotion état que quand un petit type integer est un opérande d'une opération, son type à obtenir une promotion àint
, qui est signé. Ce phénomène, peu importe si le type a été signé ou non signé.Dans le cas de la
signed char
, le signe sera préservée et il sera promu à unint
contenant la valeur de -5. Dans le cas de launsigned char
, il contient une valeur qui est de 251 (0xFB ). Il sera promu à unint
contenant la même valeur. Vous vous retrouvez avecÀ l'entier le cas où vous avez les types
(signed int) == (unsigned int)
. Ils ne sont pas de petits types d'entiers, de sorte que le nombre entier promotions ne s'appliquent pas. Au lieu de cela, ils sont équilibrés par l'habitude de l'arithmétique des conversions, qui indiquent que si les deux opérandes ont la même "rang" (taille), mais différente de ce paramètre, la signature de l'opérande est converti du même type que la non-signé une. Vous vous retrouvez avecunsigned int
siint
n'est pas assez grand pour représenter toutes les valeurs de type de moins de conversion de grade; par exemple, supposonsint
etshort
sont à la fois 16 bits types; ensuite, la conversion deunsigned short
àint
ne peut pas conserver les valeurs en général, donc, nous allons avecunsigned int
au lieuint
si je convertir explicitement les variables commeif((unsigned char) 128 == (signed char) -128)
?(unsigned short)((unsigned short)65535u * (unsigned short)65535u)
donnerait 1 plutôt que de lancer des ogives nucléaires? Y aurait-il une manière de calculer les 16 bits de poids faible du produit de deux nombres 16 bits serait efficace sur 16 bits de la machine, mais garanti correct sur une machine 32 bits?Cool question!
La
int
comparaison fonctionne, parce que les deux entiers contiennent exactement les mêmes bits, de sorte qu'ils sont essentiellement les mêmes. Mais que dire de lachar
s?Ah, C implicitement favorise
char
s àint
s à diverses occasions. C'est l'un d'entre eux. Votre code ditif(a==b)
, mais ce que le compilateur s'avère en fait que de est:(int)a
est de 5, mais(int)b
est de 251. Ce ne sont pas les mêmes.EDIT: Comme @Carbonique Acide souligné,
(int)b
est de 251 seulement si unchar
est de 8 bits. Siint
est une longueur de 32 bits,(int)b
est -32764.REDIT: Il y a tout un tas de commentaires de discuter de la nature de la réponse si un octet de 8 bits. La seule différence dans ce cas est que
(int)b
n'est pas 251 mais d'une autre positif nombre, ce qui n'est pas -5. Ce n'est pas vraiment pertinent pour la question qui est toujours très cool.(int)b is 251
- sichar
est de 8 bits, dont elle n'a pas besoin de l'être. Pour mieux dire,(1 << CHAR_BIT) - 5
.char
est de 8 bits" et "siint
est de 32 bits" serait un meilleur choix.int
comparaison ne fonctionne pas parce que les variables contiennent les mêmes bits, mais parce que leurs valeurs comparer égalité après la conversion; le langage C pour la plupart ne se soucient pas de la représentation -(unsigned)-1 == UINT_MAX
est vrai même si la connexion de l'ampleur de la représentation est utilisée, où, contrairement aux en complément à deux, la conversion n'est pas un noopint
et de 4 à 36 bitslong
, mais au moins, ces machines ont été conçues dans les années 1960, alors qu'ils avaient une excuse. 😀char
est un classique de 15 bits (au lieu de 32) etint
est de 32 bits alors(int)(unsigned char)-5
est32763
(pas -32764). Unsigned l'arithmétique est toujours bien défini, bien qu'il repose sur les bits de taille. Pour k bits, il vous suffit de calculer la valeur () mod 2<sup>k</sup>. Signé potentiellement devient malpropre, mais si la machine est en complément à deux—plus—il n'est pas mauvais.Bienvenue à entier de promotion de la. Si je citerai le site:
C peut être vraiment déroutant quand vous faites des comparaisons de ce genre, j'ai récemment perplexe certains de mes non-programmation en C des amis avec les suivants tease:
Qui en effet n'a imprimer
This cannot be happening :(
et apparemment démontre que 25 est plus petit que -1!Ce qui se passe en dessous, cependant, est que -1 est représenté comme un entier non signé qui, en raison de la sous-bits de la représentation est égale à 4294967295 sur un système 32 bits. Et, naturellement, 25 est inférieure à 4294967295.
Si nous avons cependant explicitement cast le
size_t
type retourné parstrlen
comme un entier signé:Puis il va comparer 25 contre -1 et tout ira bien avec le monde.
Un bon compilateur doit vous avertir au sujet de la comparaison entre un entier non signé et entier signé et pourtant, il est toujours si facile de manquer (surtout si vous n'avez pas d'activer les avertissements).
C'est particulièrement déroutant pour les programmeurs Java comme tous les types primitifs il y a signée. Voici ce que James Gosling (l'un des créateurs de Java) avait à dire sur le sujet:
Byte
types de Pascal a posé aucune difficulté. La seule unsigned types qui sont à toutes les problématiques sont celles qui sont plus grandes que la valeur par défaut entier de taille.(int)(strlen(string)) < -1
œuvres. Vous avez seulement changé côté gauche de comparaison, la droite sera toujours 4294967295 selon l'explication précédente. (cc @Xolve )size_t
résultat qui ne peut pas être représenté comme uneint
. Ainsi, tous les opérandes de la comparaison sont promus à launsigned int
.La représentation hexadécimale de la
-5
est:signed char
:0xfb
signed int
:0xfffffffb
Lorsque vous convertissez un signé nombre un nombre non signé, ou vice versa, le compilateur ne ... rien de précis. Qu'est ce qu'il y a à faire? Le nombre est soit convertibles ou il ne l'est pas, auquel cas indéfini ou la mise en œuvre définies par le comportement suit (je n'ai pas réellement vérifié que) et le plus efficace de mise en œuvre définies par le comportement est de ne rien faire.
Ainsi, la représentation hexadécimale de la
(unsigned <type>)-5
est:unsigned char
:0xfb
unsigned int
:0xfffffffb
Semble familière? Ils sont peu-à-peu la même chose que les versions signées.
Lorsque vous écrivez
if (a == b)
, oùa
etb
sont de typechar
, ce que le compilateur est en fait nécessaire pour lire estif ((int)a == (int)b)
. (C'est que "l'entier de la promotion" que tout le monde est de taper sur le sujet.)Donc, ce qui arrive quand nous convertir
char
àint
?signed char
à 32 bitssigned int
:0xfb
->0xfffffffb
-5
ci-dessus!unsigned char
à 32 bitssigned int
:0xfb
->0x000000fb
Donc,
a == b
vraiment0xfffffffb == 0x000000fb
=> pas de match!Et,
c == d
vraiment0xfffffffb == 0xfffffffb
=> match!"Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type."
When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
/--/"Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised."
Mon point est: vous n'avez pas reçu un avertissement lors de la compilation "la comparaison des entiers signés et non signés expression"?
Le compilateur essaie de vous informer qu'il est en droit de faire des trucs dingues! 🙂 Je voudrais ajouter un truc fou qui va arriver en utilisant de grandes valeurs, à proximité de la capacité du type primitif. Et
est l'attribution certainement un grand valeur pour d, c'est l'équivalent (même si, probablement pas la garantie d'être l'équivalent) à:
Edit:
Cependant, il est intéressant de remarquer que seule la seconde comparaison donne un avertissement (vérifier le code). Donc, cela signifie que le compilateur en appliquant les règles de conversion est convaincu qu'il n'y aura pas d'erreurs dans la comparaison entre les
unsigned char
etchar
(pendant la comparaison, ils seront convertis en un type qui puisse représenter l'ensemble de ses valeurs possibles). Et il a raison sur ce point. Ensuite, il vous informe que ce ne sera pas le cas pourunsigned int
etint
: lors de la comparaison de l'un des 2 sera converti en un type qui ne peut pas représenter pleinement.Pour l'exhaustivité, Je l'ai vérifié aussi pour de courtes: le compilateur se comporte de la même manière que pour les caractères, et, comme prévu, il n'y a pas d'erreurs à l'exécution.
.
Liées à ce sujet, j'ai récemment demandé cette question (encore, C++ orienté).