Signé non signé de conversion en C - est-il toujours en sécurité?
Supposons que j'ai la suite du code C.
unsigned int u = 1234;
int i = -5678;
unsigned int result = u + i;
Ce que les conversions implicites sont passe ici, et c'est le code sécurité pour toutes les valeurs de u
et i
? (Coffre-fort, dans le sens que même si résultat dans cet exemple de dépassement d'une énorme nombre positif, je pourrais revenir à un int et obtenir le résultat réel.)
Vous devez vous connecter pour publier un commentaire.
Réponse Courte
Votre
i
sera converti à un entier non signé par l'ajout deUINT_MAX + 1
, ensuite, l'ajout sera effectuée avec les valeurs non signées, résultant en un grandresult
(selon les valeurs deu
eti
).Réponse Longue
Selon le Standard C99:
Dans votre cas, nous avons un unsigned int (
u
) et signé int (i
). En se référant à (3) ci-dessus, puisque les deux opérandes ont le même rang, de votrei
devront être converti à un entier non signé.Maintenant, nous devons nous référer à (2) ci-dessus. Votre
i
sera convertie en une valeur non signée par l'ajout deUINT_MAX + 1
. Donc, le résultat dépendra de la façon dontUINT_MAX
est défini sur votre mise en œuvre. Il sera grand, mais il ne débordera pas, parce que:Bonus: Conversion Arithmétique Semi-WTF
Vous pouvez utiliser ce lien pour essayer ce en ligne: https://repl.it/repls/QuickWhimsicalBytes
Bonus: Conversion Arithmétique Des Effets Secondaires
Arithmétique des règles de conversion peut être utilisée pour obtenir la valeur de
UINT_MAX
par l'initialisation d'une valeur non signée à-1
, c'est à dire:Ceci est garanti pour être portable, indépendamment de la signature de numéro de représentation du système en raison de la conversion des règles décrites ci-dessus. Voir ce DONC, la question pour plus d'informations: Est-il sécuritaire d'utiliser -1 pour définir tous les bits à vrai?
Conversion de l'signé non signé ne pas nécessairement juste de copier ou de réinterpréter la représentation de la valeur signée. Citant le standard C (C99 6.3.1.3):
Pour le complément à deux de la représentation qui est presque universel, ces jours-ci, les règles ne correspondent à réinterpréter les bits. Mais pour d'autres représentations (signe-et-grandeur ou un " complément), le C de mise en œuvre doivent encore prendre des dispositions pour le même résultat, ce qui signifie que la conversion ne peut pas simplement copier les bits. Par exemple, (unsigned)-1 == UINT_MAX, indépendamment de la représentation.
En général, les conversions en C sont définis pour fonctionner sur des valeurs et non sur les représentations.
Pour répondre à la question d'origine:
La valeur de i est converti en unsigned int, produisant
UINT_MAX + 1 - 5678
. Cette valeur est ensuite ajoutée à la valeur non signée 1234, produisantUINT_MAX + 1 - 4444
.(Contrairement à unsigned débordement, signé débordement invoque un comportement indéfini. Wraparound est commun, mais n'est pas garanti par la norme C -- et les optimisations du compilateur peut faire des ravages sur le code qui fait des suppositions injustifiées.)
Se référant à la bible:
Quand un non signées et un signé variable sont ajoutés (ou toute opération binaire), les deux sont implicitement converti en unsigned, qui serait dans ce cas aboutir à un formidable résultat.
De sorte qu'il est sûr dans le sens de ce que le résultat peut être énorme et le mal, mais il ne sera jamais de plantage.
Lors de la conversion de signé non signé il y a deux possibilités. Les numéros qui ont été à l'origine positive rester (ou sont interprétés comme) la même valeur. Nombre qui ont été à l'origine négative va maintenant être interprété comme le plus grand des nombres positifs.
Comme on en a déjà répondu, vous pouvez convertir le dos-et-vient entre signés et non signés, sans problème. La frontière de cas pour les entiers signés est de -1 (0xFFFFFFFF). Essayez l'addition et la soustraction à partir de cela et vous verrez que vous pouvez lancer en arrière et corriger.
Toutefois, si vous allez être en jetant en arrière et en avant, je vous conseille de nommer vos variables telles qu'il est évident que le type qu'ils sont, par exemple:
Il est beaucoup trop facile de se laisser distraire par des questions plus importantes et d'oublier la variable qui est ce type, s'ils sont nommés, sans un soupçon. Vous ne voulez pas pour jeter pour un unsigned et ensuite l'utiliser comme un tableau d'index.
je vais être converti en un entier non signé.
Sûr dans le sens de l'être bien définis oui (voir https://stackoverflow.com/a/50632/5083516 ).
Les règles écrites sont généralement difficiles à lire des normes de parler, mais essentiellement ce que la représentation a été utilisée dans l'signé entier non signé entier contient un complément de 2 représentation du nombre.
L'Addition, la soustraction et la multiplication fonctionnera correctement sur ces chiffres résultant en un autre nombre entier non signé contenant un complément à deux du nombre qui représente la "vraie raison".
de la division et de la coulée de plus grand entier non signé de types bien définis résultats, mais ces résultats ne seront pas complément de 2 représentations de la "vraie raison".
Tandis que les conversions de signé non signé sont définies par la norme et l'inverse est mise en œuvre définies par gcc et msvc définir la conversion de telle sorte que vous obtiendrez le "vrai" résultat lors de la conversion d'un complément de 2 numéros stockés dans un entier non signé de retour d'un entier signé. J'attends de vous la trouverez tout autre comportement obscur sur les systèmes qui n'utilisent pas de complément de 2 pour les entiers signés.
https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation
https://msdn.microsoft.com/en-us/library/0eex498h.aspx
Horrible Réponses À Gogo
Ozgur Ozcitak
Ce qui est totalement faux.
Tapis Fredriksson
C'est également faux. Unsigned ints peuvent être promus à l'ints devraient-ils avoir la même précision en raison de rembourrage bits du type non signé.
smh
Mal. Peut-être qu'il fait, et peut-être qu'il ne l'est pas.
Mal. Soit c'est un comportement indéfini si elle provoque le débordement ou la valeur est conservée.
Anonyme
Mal. Dépend de la précision d'un int par rapport à un unsigned int.
Taylor Prix
Mal. Essayez de stocker une valeur en dehors de la portée d'un entier signé de résultats dans un comportement indéfini.
Maintenant, je peux enfin répondre à la question.
Devrait la précision de l'int égal à unsigned int, u sera promu à un signed int et vous obtiendrez la valeur -4444 à partir de l'expression (u+i). Maintenant, faudrait-u et j'ai d'autres valeurs, vous pouvez obtenir un débordement et un comportement indéfini, mais avec ceux nombre exact, vous obtiendrez -4444 [1]. Cette valeur de type int. Mais vous essayez de stocker cette valeur dans un unsigned int donc, ça va être lancé pour un unsigned int, et la valeur que le résultat sera à la fin avoir serait (UINT_MAX+1) - 4444.
Devrait la précision de unsigned int plus grand que celui d'un int, signé int sera promu à un unsigned int rendement de la valeur (UINT_MAX+1) - 5678 qui seront ajoutés à l'autre unsigned int 1234. Devraient u et j'ai d'autres valeurs, qui font de l'expression de l'automne à l'extérieur de la plage de {0..UINT_MAX} la valeur (UINT_MAX+1) sera ajouté ou soustrait jusqu'à ce que le résultat NE tombent à l'intérieur de la plage de {0..UINT_MAX) et pas d'un comportement indéfini va se produire.
Ce qui est de la précision?
Entiers ont un rembourrage bits, signe bits, et la valeur des bits. Des entiers non signés ne disposez pas d'un bit de signe, évidemment. Unsigned char est en outre garanti de ne pas avoir de remplissage bits. Le nombre de valeurs de bits d'un entier a est quelle précision il est.
[Astuces]
La macro sizeof macro seul ne peut pas être utilisé pour déterminer la précision d'un nombre entier si padding bits sont présents. Et la taille d'un octet de ne pas être un octet (huit bits), tel que défini par le C99.
[1] Le dépassement peut se produire à un des deux points. Avant l'ajout (cours de promotion) - lorsque vous avez un unsigned int qui est trop grand pour s'adapter à l'intérieur d'un int. Le débordement peut également se produire après la outre, même si la unsigned int est dans la gamme d'un int, après la outre le résultat peut encore débordement.
Sur une autre note, je suis un jeune étudiant diplômé en essayant de trouver du travail 😉
int
est converti àunsigned int
lorsque l'arithmétique des conversions les appliquer.int
ouunsigned int
un de ces types, où quelque chose du typeunsigned int
ouint
est prévu. Le "ou égal" a été ajouté dans TC2 pour permettre à des types énumérés de conversion de rang égal àint
ouunsigned int
être converti en l'un de ces types. Il n'a jamais été prévu que la promotion décrit serait de convertir entreunsigned int
etint
. Le type le plus commun de détermination entreunsigned int
etint
est toujours régie par 6.3.1.8, même après l'TC2.unsigned int
àint
débordements, il n'y a pas un comportement indéfini. Le résultat est soit mise en œuvre ou défini par une mise en œuvre définies par le signal est déclenché.int
ouunsigned int
.