Einem unsigned int negative Zahlen zuweisen?

Lesezeit: 7 Minuten

Benutzeravatar von ipkiss
ipkiss

In der Programmiersprache C unsigned int wird verwendet, um nur positive Werte zu speichern. Wenn ich jedoch den folgenden Code ausführe:

unsigned int x = -12;
printf("%d", x);

Die Ausgabe ist immer noch -12. Ich dachte, es hätte ausgedruckt werden sollen: 12, oder verstehe ich etwas falsch?

  • Sie lügen den Compiler an: Sie sagen dem Compiler, dass Sie etwas geben werden printf ein int (das "%d"), aber stattdessen gibst du ihm ein unsigned. Lügen Sie den Compiler nicht an

    – pmg

    2. März 2011 um 15:37 Uhr


  • @Joachim: Der Compiler führt die ‘üblichen arithmetischen Konvertierungen’ durch (siehe 3.2.1.5). “… Andernfalls, wenn einer der Operanden den Typ unsigned int hat, wird der andere Operand in unsigned int konvertiert …” und -12 umgewandelt in vorzeichenlose Ergebnisse in (UINT_MAX + 1) - 12.

    – pmg

    2. März 2011 um 16:01 Uhr

  • @Joachim: das gcc-Flag -Wsign-conversion (enthalten in -Wconversion) kann verwendet werden, um davor zu warnen. Wie Sie jetzt wissen, ist es nicht Teil von -Wall oder -Wextra.

    – pmg

    2. März 2011 um 16:12 Uhr


  • @Joachim: Ich sehe keinen Grund, warum der Compiler Warnungen für eine absolut vernünftige Verwendung der Sprache ausgeben sollte. Es ist eine Schande, dass die Besonderheiten der Integer-Semantik von C normalerweise nicht früh in Büchern und Kursen eingeführt werden, aber das ist nicht wirklich eine Entschuldigung dafür, die bevorzugte Warnstufe des Compilers auf Leute zuzuschneiden, die die Sprache, in der sie programmieren, nicht kennen …

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    3. März 2011 um 0:54 Uhr

  • @R: Eigentlich schade, dass die GCC Compiler liegt an der Benutzer mit -Wallda es nicht “alle” Warnungen aktiviert.

    – Benutzer541686

    3. März 2011 um 7:49 Uhr

Benutzeravatar von Tim Oltrogge
Tim Oltrogge

Das -12 rechts von Ihrem Gleichheitszeichen wird als vorzeichenbehaftete Ganzzahl (wahrscheinlich 32 Bit groß) eingerichtet und hat den hexadezimalen Wert 0xFFFFFFF4. Der Compiler generiert Code, um diese vorzeichenbehaftete Ganzzahl in Ihre vorzeichenlose Ganzzahl zu verschieben x das ist auch eine 32-Bit-Entität. Der Compiler geht davon aus, dass Sie rechts vom Gleichheitszeichen nur einen positiven Wert haben, also verschiebt er einfach alle 32 Bits hinein x. x hat jetzt den wert 0xFFFFFFF4 welches ist 4294967284 wenn sie als positive Zahl interpretiert wird. Aber die printf Format von %d sagt, dass die 32 Bit als vorzeichenbehaftete Ganzzahl zu interpretieren sind, damit Sie erhalten -12. Wenn Sie verwendet hatten %u es hätte gedruckt wie 4294967284.

In beiden Fällen erhalten Sie nicht das, was Sie erwartet haben, da die C-Sprache dem Autor des Codes “vertraut”, nur nach “vernünftigen” Dingen zu fragen. Dies ist in C üblich. Wenn Sie einen Wert zuweisen möchten x und nicht sicher waren, ob der Wert auf der rechten Seite des Gleichheitszeichens positiv war, hätten Sie schreiben können unsigned int x = abs(-12); und zwang den Compiler, Code zu generieren, um den absoluten Wert einer vorzeichenbehafteten Ganzzahl zu nehmen, bevor er in die vorzeichenlose Ganzzahl verschoben wird.

  • Vieles davon ist technisch falsch. Im unsigned int x = -12;das -12 ist ein ganzzahliger konstanter Ausdruck des Typs int. Das wird umgerechnet unsigned int durch wiederholtes Addieren (oder Subtrahieren) UINT_MAX + 1 auf den Wert bis ein Wert zwischen 0 und UINT_MAX (beide inklusive) erhalten wird, ist dieser Wert das Ergebnis der Konvertierung. Auf Einerkomplement- oder Zeichen-und-Größen-Maschinen ändert das das Bitmuster des Werts; Auf den häufigeren Zweierkomplementmaschinen ist es nur eine andere Interpretation des gleichen Bitmusters.

    – Daniel Fischer

    24. Juni 2012 um 19:30 Uhr

  • Dieser Teil ist jedoch vollständig durch den Standard und danach definiert unsigned int x = -12;der Wert von x muss immer sein UINT_MAX - 11. Die nächste Zeile, printf("%d", x); ruft undefiniertes Verhalten auf, da die %d Der Konvertierungsbezeichner erfordert eine signierte int und der Wert von x ist nicht in beiden vertreten unsigned int und int. Das übliche Verhalten ist natürlich die Neuinterpretation des Bitmusters, auf Einerkomplementmaschinen, die in diesem Fall nachgeben würden -11auf Vorzeichen und Größe mit 32-Bit ints, -2147483636. Und auf Zweierkomplementmaschinen das beobachtete Verhalten.

    – Daniel Fischer

    24. Juni 2012 um 19:30 Uhr

  • @DanielFischer Warum ist der Wert von x nicht darstellbar in unsigned int da der Wert kleiner als ist UINT_MAX?

    – jaja

    25. Februar 2014 um 10:33 Uhr

  • @ajay Der Wert von x ist darstellbar als ein unsigned intaber nicht als int (es sei denn, die Implementierung ist so seltsam, dass es unsigned ints haben ein Füllbit, sodass der Bereich ein Unterbereich von ist int Angebot). Drucken ein unsigned int mit dem %d Conversion-Spezifizierer ist ein undefiniertes Verhalten, es sei denn, der Wert ist darstellbar in beide Typen.

    – Daniel Fischer

    25. Februar 2014 um 11:18 Uhr

  • Für mich ergibt das Sinn. Persönliche Anekdote: Ich habe versucht, das Vorzeichen einer Ganzzahl zu entfernen, indem ich es in ein Int ohne Vorzeichen umwandelte und es den neuen Wert speichern ließ. Habe natürlich herausgefunden, dass C++ so nicht funktioniert.

    – Montana Burr

    11. November 2016 um 1:37 Uhr

Benutzeravatar von Binary Worrier
Binäre Besorgnis

Das int ist unsinged, aber du hast es gesagt printf um es als einen signierten int zu betrachten.

Versuchen

unsigned int x = -12; printf("%u", x);

Es wird nicht “12” gedruckt, sondern der maximale Wert eines unsigned int minus 11.

Übung für den Leser ist, herauszufinden, warum 🙂

  • “11 oder 12” ist falsch. Das Ergebnis ist wohldefiniert und ist UINT_MAX-11nicht UINT_MAX-12.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    3. März 2011 um 0:55 Uhr

  • @R: Ich konnte mich nicht erinnern, ob es max-11 war oder max – 12, daher sagte ich “Minus 11 oder 12” (was technisch korrekt ist, da es war eine von diesen). Danke für den Hinweis, dass es -11 ist, ich werde die Antwort ändern, um dies zu reflektieren, danke.

    – Binäre Sorge

    3. März 2011 um 7:40 Uhr

  • Letztendlich ist es das Zweierkomplement der Zahl

    – niyasc

    13. April 2015 um 5:28 Uhr

Die Übergabe von %d an printf weist printf an, das Argument als vorzeichenbehaftete Ganzzahl zu behandeln, unabhängig davon, was Sie tatsächlich übergeben. Verwenden Sie %u, um unsigniert zu drucken.

  • Einfach und verständlich, beste Antwort!

    – Eugen Sunic

    30. August 2016 um 11:33 Uhr

  • Ich schätze diese Antwort mehr. Es kommt auf den Punkt. Vielen Dank.

    – rayryeng

    31. Januar 2017 um 16:43 Uhr

Es hat alles mit der Interpretation des Wertes zu tun.

Wenn Sie 16-Bit-Ganzzahlen mit und ohne Vorzeichen annehmen, dann hier einige Beispiele, die nicht ganz korrekt sind, aber das Konzept veranschaulichen.

0000 0000 0000 1100 unsigned int und signed int Wert 12

1000 0000 0000 1100 vorzeichenbehafteter Ganzzahlwert -12 und eine große vorzeichenlose Ganzzahl.

Bei Ganzzahlen mit Vorzeichen ist das linke Bit das Vorzeichenbit. 0 = positiv 1 = negativ

Bei Ganzzahlen ohne Vorzeichen gibt es kein Vorzeichenbit. Mit dem linken Bit können Sie stattdessen eine größere Zahl speichern.

Der Grund, warum Sie nicht sehen, was Sie erwarten, ist das.

unsigned int x = -12, nimmt -12 als Ganzzahl und speichert sie in x. x ist vorzeichenlos, was also ein Vorzeichenbit war, ist jetzt ein Teil des Werts.

Mit printf können Sie dem Compiler mitteilen, wie ein Wert angezeigt werden soll.

%d bedeutet, dass es so angezeigt wird, als wäre es ein signierter Int. %u bedeutet, dass es so angezeigt wird, als wäre es ein unsigned int.

c lässt dich solche Sachen machen. Sie, der Programmierer, haben die Kontrolle.

Ein bisschen wie eine Schusswaffe. Es ist ein Werkzeug. Sie können es richtig verwenden, um mit bestimmten Situationen umzugehen, oder falsch, um einen Ihrer Zehen zu entfernen.

Ein möglicherweise nützlicher Fall ist der folgende

unsigned int allBitsOn = -1;

Dieser bestimmte Wert setzt alle Bits auf 1

1111 1111 1111 1111

das kann manchmal nützlich sein.

Benutzeravatar von Linus Kleen
Linus Kleen

printf('%d', x); 

Bedeutet, eine vorzeichenbehaftete Ganzzahl auszugeben. Du musst stattdessen Folgendes schreiben:

printf('%u', x);

Außerdem wird immer noch nicht “12” gedruckt, sondern “4294967284”.

Leichtigkeitsrennen im Benutzeravatar von Orbit
Leichtigkeitsrennen im Orbit

Sie speichern positive Werte. Aber Sie geben den (sehr hohen) positiven Wert als vorzeichenbehaftete Ganzzahl aus, sodass er erneut neu interpretiert wird (in einer implementierungsdefinierten Weise, möchte ich hinzufügen).

Verwenden Sie das Format-Flag "%u stattdessen.

R.. GitHub STOP HELPING ICEs Benutzeravatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Ihr Programm hat ein undefiniertes Verhalten, weil Sie den falschen Typ übergeben haben printf (Du hast ihm gesagt, dass du eine passieren würdest int aber du hast eine bestanden unsigned int). Schätzen Sie sich glücklich, dass das “Einfachste” für die Implementierung darin bestand, einfach stillschweigend den falschen Wert auszugeben und nicht zu einem Code zu springen, der etwas Schädliches tut …

  • das Übergeben einer vorzeichenlosen ganzen Zahl, wo ein Variablenargument des entsprechenden vorzeichenbehafteten Typs erwartet wird, ist tatsächlich wohldefiniert, wenn der Wert in beiden Typen darstellbar ist (siehe C99 7.15.1.1 §2); Dies ist hier jedoch nicht der Fall, aber jede vernünftige Implementierung der C-Sprache wird den Wert einfach über „Typ-Wortspiel“ übersetzen (siehe Fußnote 82 auf Seite 73).

    – Christoph

    3. März 2011 um 12:13 Uhr

1411690cookie-checkEinem unsigned int negative Zahlen zuweisen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy