Kurze Antwort
Ihr i
wird durch Hinzufügen in eine vorzeichenlose Ganzzahl konvertiertUINT_MAX + 1
, dann wird die Addition mit den vorzeichenlosen Werten ausgeführt, was zu einem großen Wert führt result
(abhängig von den Werten von u
und i
).
Lange Antwort
Nach dem C99-Standard:
6.3.1.8 Übliche arithmetische Umrechnungen
- Wenn beide Operanden denselben Typ haben, ist keine weitere Konvertierung erforderlich.
- Andernfalls wird der Operand mit dem Typ des Konvertierungsrangs mit geringerer Ganzzahl in den Typ des Operanden mit dem höheren Rang konvertiert, wenn beide Operanden Ganzzahltypen mit Vorzeichen oder beide Ganzzahltypen ohne Vorzeichen haben.
- Wenn andernfalls der Operand mit vorzeichenlosem Integer-Typ einen Rang hat, der größer oder gleich dem Rang des Typs des anderen Operanden ist, wird der Operand mit vorzeichenbehaftetem Integer-Typ in den Typ des Operanden mit vorzeichenlosem Integer-Typ konvertiert.
- Wenn andernfalls der Typ des Operanden mit vorzeichenbehaftetem Integer-Typ alle Werte des Typs des Operanden mit vorzeichenlosem Integer-Typ darstellen kann, wird der Operand mit vorzeichenlosem Integer-Typ in den Typ des Operanden mit vorzeichenbehaftetem Integer-Typ konvertiert.
- Andernfalls werden beide Operanden in den vorzeichenlosen Integer-Typ konvertiert, der dem Typ des Operanden mit vorzeichenbehaftetem Integer-Typ entspricht.
In Ihrem Fall haben wir ein vorzeichenloses int ( u
) und ein signiertes int ( i
). Mit Bezug auf (3), da beide Operanden den gleichen Rang haben, Ihr i
werden müssen umgewandelt in eine ganze Zahl ohne Vorzeichen.
6.3.1.3 Ganzzahlen mit und ohne Vorzeichen
- Wenn ein Wert mit einem ganzzahligen Typ in einen anderen ganzzahligen Typ als _Bool konvertiert wird und der Wert durch den neuen Typ dargestellt werden kann, bleibt er unverändert.
- Wenn der neue Typ nicht signiert ist, wird der Wert konvertiert, indem wiederholt ein Wert mehr als der Maximalwert addiert oder subtrahiert wird, der im neuen Typ dargestellt werden kann, bis der Wert im Bereich des neuen Typs liegt.
- Andernfalls wird der neue Typ signiert und der Wert kann nicht darin dargestellt werden. Entweder ist das Ergebnis implementierungsdefiniert oder es wird ein implementierungsdefiniertes Signal ausgelöst.
Nun müssen wir uns auf (2) oben beziehen. Ihr i
wird durch Hinzufügen in einen vorzeichenlosen Wert umgewandelt UINT_MAX + 1
. Das Ergebnis hängt also davon ab, wie UINT_MAX
es in Ihrer Implementierung definiert ist. Es wird groß sein, aber es wird nicht überlaufen, weil:
6.2.5 (9)
Eine Berechnung mit vorzeichenlosen Operanden kann niemals überlaufen, da ein Ergebnis, das nicht durch den resultierenden vorzeichenlosen Ganzzahltyp dargestellt werden kann, modulo um die Zahl reduziert wird, die eins größer ist als der größte Wert, der durch den resultierenden Typ dargestellt werden kann.
Bonus: Arithmetische Umrechnung Semi-WTF
#include <stdio.h>
int main(void)
{
unsigned int plus_one = 1;
int minus_one = -1;
if(plus_one < minus_one)
printf("1 < -1");
else
printf("boring");
return 0;
}
Sie können diesen Link verwenden, um dies online zu versuchen: https://repl.it/repls/QuickWhimsicalBytes
Bonus: Nebeneffekt der arithmetischen Umwandlung
Arithmetische Konvertierungsregeln können verwendet werden, um den Wert von zu erhalten, UINT_MAX
indem ein vorzeichenloser Wert initialisiert wird -1
, dh:
unsigned int umax = -1; // umax set to UINT_MAX
Aufgrund der oben beschriebenen Konvertierungsregeln ist dies unabhängig von der vorzeichenbehafteten Nummerndarstellung des Systems garantiert portierbar. Weitere Informationen finden Sie in dieser SO-Frage: Ist es sicher, -1 zu verwenden, um alle Bits auf true zu setzen?
Die Konvertierung von signiert in nicht signiert kopiert oder interpretiert nicht unbedingt nur die Darstellung des signierten Werts. Zitieren des C-Standards (C99 6.3.1.3):
Für die Komplementdarstellung der beiden, die heutzutage nahezu universell ist, entsprechen die Regeln der Neuinterpretation der Bits. Bei anderen Darstellungen (Vorzeichen und Größe oder Einsenkomplement) muss die C-Implementierung dennoch das gleiche Ergebnis erzielen, was bedeutet, dass die Konvertierung nicht nur die Bits kopieren kann. Zum Beispiel (ohne Vorzeichen) -1 == UINT_MAX, unabhängig von der Darstellung.
Im Allgemeinen werden Konvertierungen in C so definiert, dass sie mit Werten und nicht mit Darstellungen arbeiten.
So beantworten Sie die ursprüngliche Frage:
Der Wert von i wird in int ohne Vorzeichen umgewandelt, was ergibt
UINT_MAX + 1 - 5678
. Dieser Wert wird dann zu dem vorzeichenlosen Wert 1234 addiert, was ergibtUINT_MAX + 1 - 4444
.(Im Gegensatz zu einem nicht signierten Überlauf ruft ein signierter Überlauf ein undefiniertes Verhalten hervor. Wraparound ist häufig, wird jedoch vom C-Standard nicht garantiert. Compiler-Optimierungen können den Code zerstören, der ungerechtfertigte Annahmen trifft.)
quelle
Bezugnehmend auf die Bibel :
quelle
Wenn eine vorzeichenlose und eine vorzeichenbehaftete Variable hinzugefügt werden (oder eine beliebige binäre Operation), werden beide implizit in vorzeichenlose Variablen konvertiert, was in diesem Fall zu einem großen Ergebnis führen würde.
Es ist also sicher in dem Sinne, dass das Ergebnis riesig und falsch sein könnte, aber es wird niemals abstürzen.
quelle
Bei der Konvertierung von vorzeichenbehaftet in vorzeichenlos gibt es zwei Möglichkeiten. Ursprünglich positive Zahlen bleiben (oder werden als solche interpretiert) der gleiche Wert. Ursprünglich negative Zahlen werden nun als größere positive Zahlen interpretiert.
quelle
Wie bereits beantwortet, können Sie problemlos zwischen signiert und nicht signiert wechseln. Der Grenzfall für vorzeichenbehaftete Ganzzahlen ist -1 (0xFFFFFFFF). Wenn Sie versuchen, das zu addieren und davon zu subtrahieren, werden Sie feststellen, dass Sie zurückwerfen können und es korrekt haben.
Wenn Sie jedoch hin und her werfen möchten, würde ich dringend empfehlen, Ihre Variablen so zu benennen, dass klar ist, um welchen Typ es sich handelt, z.
Es ist viel zu leicht, sich von wichtigeren Themen ablenken zu lassen und zu vergessen, welche Variable welcher Typ ist, wenn sie ohne Hinweis benannt werden. Sie möchten nicht in ein vorzeichenloses Zeichen umwandeln und dieses dann als Array-Index verwenden.
quelle
Ich werde in eine vorzeichenlose Ganzzahl konvertiert.
Sicher im Sinne einer guten Definition ja (siehe https://stackoverflow.com/a/50632/5083516 ).
Die Regeln sind in der Regel schwer lesbar geschrieben, aber im Wesentlichen enthält die vorzeichenlose Ganzzahl, unabhängig davon, welche Darstellung in der vorzeichenbehafteten Ganzzahl verwendet wurde, eine 2er-Komplementdarstellung der Zahl.
Addition, Subtraktion und Multiplikation funktionieren bei diesen Zahlen korrekt, was zu einer weiteren vorzeichenlosen Ganzzahl führt, die eine Zweierkomplementzahl enthält, die das "echte Ergebnis" darstellt.
Division und Casting in größere vorzeichenlose Ganzzahltypen haben genau definierte Ergebnisse, aber diese Ergebnisse sind keine 2er-Komplementdarstellungen des "realen Ergebnisses".
Während Konvertierungen von vorzeichenbehafteten in vorzeichenlose durch den Standard definiert sind, ist die Umkehrung implementierungsdefiniert. Sowohl gcc als auch msvc definieren die Konvertierung so, dass Sie das "echte Ergebnis" erhalten, wenn Sie die in einer vorzeichenlosen Ganzzahl gespeicherte Zweierkomplementzahl zurück in eine vorzeichenbehaftete Ganzzahl konvertieren . Ich gehe davon aus, dass Sie nur auf obskuren Systemen ein anderes Verhalten finden, die das 2er-Komplement nicht für vorzeichenbehaftete Ganzzahlen verwenden.
https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation https://msdn.microsoft.com/en-us/library/0eex498h.aspx
quelle
Schreckliche Antworten in Hülle und Fülle
Ozgur Ozcitak
Das ist völlig falsch.
Mats Fredriksson
Das ist auch falsch. Vorzeichenlose Ints können zu Ints heraufgestuft werden, wenn sie aufgrund von Füllbits im vorzeichenlosen Typ die gleiche Genauigkeit haben.
smh
Falsch. Vielleicht tut es und vielleicht tut es nicht.
Falsch. Es ist entweder ein undefiniertes Verhalten, wenn es einen Überlauf verursacht, oder der Wert bleibt erhalten.
Anonym
Falsch. Hängt von der Genauigkeit eines int relativ zu einem vorzeichenlosen int ab.
Taylor Price
Falsch. Der Versuch, einen Wert außerhalb des Bereichs einer vorzeichenbehafteten Ganzzahl zu speichern, führt zu undefiniertem Verhalten.
Jetzt kann ich endlich die Frage beantworten.
Sollte die Genauigkeit von int gleich int ohne Vorzeichen sein, wird u zu einem vorzeichenbehafteten int heraufgestuft und Sie erhalten den Wert -4444 aus dem Ausdruck (u + i). Wenn u und ich andere Werte haben, kann es zu einem Überlauf und undefiniertem Verhalten kommen, aber mit diesen genauen Zahlen erhalten Sie -4444 [1]. . Dieser Wert hat den Typ int. Sie versuchen jedoch, diesen Wert in einem vorzeichenlosen Int zu speichern, sodass er dann in ein vorzeichenloses Int umgewandelt wird und der Wert, den das Ergebnis ergibt, (UINT_MAX + 1) - 4444 lautet.
Sollte die Genauigkeit des vorzeichenlosen int größer sein als die eines int, wird das vorzeichenbehaftete int zu einem vorzeichenlosen int heraufgestuft, was den Wert (UINT_MAX + 1) - 5678 ergibt, der zu dem anderen vorzeichenlosen int 1234 addiert wird. Sollten u und ich haben Bei anderen Werten, bei denen der Ausdruck außerhalb des Bereichs {0..UINT_MAX} liegt, wird der Wert (UINT_MAX + 1) entweder addiert oder subtrahiert, bis das Ergebnis innerhalb des Bereichs {0..UINT_MAX) liegt und kein undefiniertes Verhalten auftritt .
Was ist Präzision?
Ganzzahlen haben Füllbits, Vorzeichenbits und Wertbits. Ganzzahlen ohne Vorzeichen haben offensichtlich kein Vorzeichenbit. Es ist weiterhin garantiert, dass vorzeichenloses Zeichen keine Füllbits enthält. Die Anzahl der Wertebits einer Ganzzahl gibt an, wie genau sie ist.
[Fallstricke]
Die Makrogröße des Makros allein kann nicht verwendet werden, um die Genauigkeit einer Ganzzahl zu bestimmen, wenn Füllbits vorhanden sind. Und die Größe eines Bytes muss kein Oktett (acht Bits) sein, wie in C99 definiert.
[1] Der Überlauf kann an einem von zwei Punkten auftreten. Entweder vor dem Hinzufügen (während der Promotion) - wenn Sie ein vorzeichenloses int haben, das zu groß ist, um in ein int zu passen. Der Überlauf kann auch nach dem Hinzufügen auftreten, selbst wenn das vorzeichenlose int im Bereich eines int lag. Nach dem Hinzufügen kann das Ergebnis dennoch überlaufen.
quelle
int
konvertiert wird,unsigned int
wenn die üblichen arithmetischen Konvertierungen gelten.int
oderunsigned int
in einen der Typen sind, bei denen etwas vom Typunsigned int
oderint
erwartet wird. Das "oder gleich" wurde in TC2 hinzugefügt, um aufgezählte Arten von Konvertierungsrang zu ermöglichen, die gleichint
oderunsigned int
in einen dieser Typen konvertiert werden. Es war nie beabsichtigt, dass die beschriebene Aktion zwischenunsigned int
und konvertiertint
. Die gemeinsame Typbestimmung zwischenunsigned int
undint
wird auch nach TC2 durch 6.3.1.8 geregelt.