Was passiert, wenn ich in C long int int zuweise?

Lesezeit: 9 Minuten

Benutzeravatar von Khaloymes
Khaloymes

In einer kürzlichen Hausaufgabe wurde mir gesagt, dass ich es verwenden soll long Variable zum Speichern eines Ergebnisses, da es sich um eine große Zahl handeln kann.

Ich entschied mich zu überprüfen, ob es wirklich wichtig für mich ist, auf meinem System (Intel Core i5/64-Bit Windows 7/gnu gcc Compiler) und fand heraus, dass der folgende Code:

printf("sizeof(char) => %d\n", sizeof(char));
printf("sizeof(short) => %d\n", sizeof(short));
printf("sizeof(short int) => %d\n", sizeof(short int));
printf("sizeof(int) => %d\n", sizeof(int));
printf("sizeof(long) => %d\n", sizeof(long));
printf("sizeof(long int) => %d\n", sizeof(long int));
printf("sizeof(long long) => %d\n", sizeof(long long));
printf("sizeof(long long int) => %d\n", sizeof(long long int));

erzeugt die folgende Ausgabe:

sizeof(char) => 1
sizeof(short) => 2
sizeof(short int) => 2
sizeof(int) => 4
sizeof(long) => 4
sizeof(long int) => 4
sizeof(long long) => 8
sizeof(long long int) => 8

Mit anderen Worten, auf meinem System int und long sind die gleichen, und was auch immer für zu groß sein wird int zu halten, wird zu groß für long auch zu halten.

Um die Hausaufgaben selbst geht es hier nicht. Ich frage mich, wie, auf einem System, wo int < longsoll ich eine zuweisen int zu lang?

Ich bin mir der Tatsache bewusst, dass es zu diesem Thema zahlreiche eng verwandte Fragen gibt, aber ich habe das Gefühl, dass die darin enthaltenen Antworten mir nicht das vollständige Verständnis dafür vermitteln, was in diesem Prozess passieren wird oder passieren kann.

Grundsätzlich versuche ich folgendes herauszufinden:

  1. Soll ich werfen long zu int vor dem Auftrag, bzw seit long
    ist kein anderer Datentyp, sondern lediglich ein Modifikator,
    wird es als unbedenklich angesehen, direkt zuzuweisen?
  2. Was passiert auf Systemen wo long > int? Wird das Ergebnis undefiniert (oder unvorhersehbar) sein oder werden die zusätzlichen Teile der Variablen weggelassen?
  3. Wie sieht das Gießen aus long zu int funktioniert in C?
  4. Wie sieht die Zuordnung aus long zu int funktioniert in C, wenn ich kein Casting verwende?

  • C hat Modifikatoren (volatile, const), aber short, long, signedund unsigned sind NICHT Modifikatoren. Sie geben eindeutige Typen an.

    – Muhende Ente

    30. November 2012 um 20:24 Uhr


  • Vorsicht dort. Wenn Sie sich beispielsweise ein Linux-AMD64-System ansehen würden. long ist 8 Bytes, wo wie int in 4. Siehe en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models für einige gängige Fälle.

    Benutzer507577

    30. November 2012 um 20:24 Uhr

  • @Rajesh: Ich glaube nicht, dass es etwas mit dem Betriebssystem zu tun hat oder Hardware. Wie groß Typen sind, ist eine (meistens) willkürliche Entscheidung der Compiler.

    – Muhende Ente

    30. November 2012 um 20:27 Uhr

  • @MooingDuck und wenn alle Compiler für eine Plattform dasselbe tun, ist es mehr oder weniger erledigt 🙂

    Benutzer507577

    30. November 2012 um 20:31 Uhr

  • @MooingDuck: Die vom Compiler (genauer gesagt von seinen Autoren) getroffene Entscheidung wird stark vom Betriebssystem und der Hardware beeinflusst. Viele Systeme haben eine ABI, die Größen von Integer-Typen angibt; danach ist es möglich, Code zu mischen, der von verschiedenen Compilern kompiliert wurde. In einigen Fällen ist die Abwärtskompatibilität ein starker Einfluss, der manchmal zu Dingen wie 32-Bit führt long auf einem 64-Bit-System.

    – Keith Thompson

    30. November 2012 um 20:36 Uhr

Benutzeravatar von Keith Thompson
Keith Thompson

Dafür sorgt die Sprache int ist mindestens 16 Bit, long ist mindestens 32 Bit, und long darstellen kann wenigstens alle Werte, die int darstellen kann.

Wenn Sie a zuweisen long Wert zu einem int Objekt, wird es implizit konvertiert. Es besteht keine Notwendigkeit für eine explizite Besetzung; Es würde lediglich dieselbe Konvertierung angeben, die sowieso stattfinden wird.

Auf Ihrem System, wo int und long zufällig die gleiche Größe und den gleichen Bereich haben, ist die Konvertierung trivial; es kopiert einfach den Wert.

Auf einem System, wo long ist breiter als intwenn der Wert nicht in eine passt int, dann ist das Ergebnis der Konvertierung implementierungsdefiniert. (Oder ab C99 kann es ein implementierungsdefiniertes Signal auslösen, aber ich kenne keinen Compiler, der das tatsächlich tut.) Was typisch Es kommt vor, dass die höherwertigen Bits verworfen werden, aber darauf sollten Sie sich nicht verlassen. (Die Regeln sind für vorzeichenlose Typen unterschiedlich; das Ergebnis der Konvertierung einer vorzeichenbehafteten oder vorzeichenlosen Ganzzahl in einen vorzeichenlosen Typ ist genau definiert.)

Wenn du musst sicher a zuweisen long Wert zu einem int Objekt, können Sie prüfen, ob es passt, bevor Sie die Zuweisung vornehmen:

#include <limits.h> /* for INT_MIN, INT_MAX */

/* ... */

int i;
long li = /* whatever */

if (li >= INT_MIN && li <= INT_MAX) {
    i = li;
}
else {
    /* do something else? */
}

Die Details von “etwas anderem” hängen davon ab, was Sie tun möchten.

Eine Korrektur: int und long sind stets unterschiedliche Typen, auch wenn sie zufällig die gleiche Größe und Darstellung haben. Arithmetische Typen sind frei konvertierbar, daher macht das oft keinen Unterschied, aber zB int* und long* sind unterschiedliche und inkompatible Typen; Sie können a nicht zuweisen long* zu einem int*oder umgekehrt, ohne explizite (und potenziell gefährliche) Umwandlung.

Und wenn Sie feststellen, dass Sie a konvertieren müssen long Wert zu int, sollten Sie als Erstes das Design Ihres Codes überdenken. Manchmal sind solche Umbauten notwendig, aber häufiger sind sie ein Zeichen dafür, dass die int dem Sie zuweisen, sollte als definiert worden sein long an erster Stelle.

  • Erstmal danke für deine Antwort! Ich nehme an (nachdem ich ein bisschen herumgegoogelt habe), dass ich zur Verwendung von INT_MIN und INT_MAX die Datei “limits.h” einfügen muss. Gibt es eine Möglichkeit, ihre Größe herauszufinden, ohne diesen Header einzufügen? Irgendwie nur von der Größe vielleicht?

    – Khaloymes

    1. Dezember 2012 um 9:35 Uhr


  • @Khaloymes: Ja, das brauchst du #include <limits.h>; Das hätte ich erwähnen sollen. Beachten Sie, dass dies Grenzen sind, keine Größen. Es gibt wahrscheinlich Möglichkeiten, sie ohne Verwendung zu berechnen <limits.h>, aber warum sich die Mühe machen? Das ist, was <limits.h> ist schließlich dafür.

    – Keith Thompson

    1. Dezember 2012 um 9:57 Uhr

  • Dieses implementierungsdefinierte Signal ist interessant. Insbesondere konnte ich in der Norm nichts finden, was besagt, dass es nur für gilt implizit Konvertierungen; Wenn eine Implementierung diesen Weg geht, wird die übliche Verwendung einer Besetzung wie “Warnen Sie mich nicht, ich weiß, was ich tue” das Verhalten nicht verhindern, wie man es intuitiv erwarten könnte.

    – Leuschenko

    10. Juni 2015 um 18:08 Uhr

  • @Leushenko: Richtig, es gilt für Konvertierungen, entweder explizit (Casts) oder implizit.

    – Keith Thompson

    10. Juni 2015 um 18:11 Uhr

  • @Lakey: Ich hätte nein gesagt, aber der C-Standard bezeichnet dies als “Abschneiden”. (Und zufälligerweise führte mich Ihre Frage zu einem Fehler im Standard. N1570 5.1.2.3p11, Beispiel 2, sagt das char c1, c2; /* ... */ c1 = c1 + c2; wird “die Summe abschneiden”, aber wenn char signiert ist, ist das Ergebnis implementierungsdefiniert. Ich nehme an, man könnte es immer noch als “Abschneiden” bezeichnen. In jedem Fall sind Beispiele nicht normativ.)

    – Keith Thompson

    19. März 2019 um 19:37 Uhr

EIN long kann immer alle Werte darstellen int. Wenn der vorliegende Wert durch den Typ der Variablen dargestellt werden kann, der Sie zuweisen, wird der Wert beibehalten.

Wenn es nicht darstellbar ist, dann ist das Ergebnis für den vorzeichenbehafteten Zieltyp formal unspezifiziert, während es für den vorzeichenlosen Zieltyp als Originalwert modulo 2 angegeben wirdnwo n ist die Anzahl der Bits in der Wertdarstellung (was nicht notwendigerweise alle Bits im Ziel sind).

In der Praxis erhalten Sie auf modernen Maschinen Verpackungen auch für signierte Typen.

Das liegt daran, dass moderne Maschinen verwenden Zweierkomplementform um vorzeichenbehaftete Ganzzahlen darzustellen, ohne dass Bits verwendet werden, um “ungültige Werte” oder ähnliches anzuzeigen – dh alle Bits, die für die Wertdarstellung verwendet werden.

Mit n Bits Wertdarstellung jeder ganzzahlige Wert ist x zugeordnet ist x+K*2n wobei die ganzzahlige Konstante K so gewählt ist, dass das Ergebnis in dem Bereich liegt, in dem die Hälfte der möglichen Werte negativ ist.

Also zB mit 32-bit int der Wert -7 wird als Bitmuster Nummer -7+2 dargestellt32 = 232-7, wenn Sie also die Zahl, für die das Bitmuster steht, als Ganzzahl ohne Vorzeichen anzeigen, erhalten Sie eine ziemlich große Zahl.

Der Grund, warum dies aufgerufen wird Zweierkomplement weil es für das binäre Zahlensystem sinnvoll ist, das Zahlensystem zur Basis zwei. Für das binäre Zahlensystem gibt es auch ein Einerkomplement (beachte die Platzierung des Apostrophs). In ähnlicher Weise gibt es für das dezimale Zahlensystem das Zehnerkomplement und das Neunerkomplement. Mit der 4-stelligen Zehnerkomplementdarstellung würden Sie -7 als 10000-7 = 9993 darstellen. Das ist wirklich alles.

  • C, beginnend mit C99, verlangt, dass vorzeichenbehaftete Ganzzahlen als Zweierkomplement, Einerkomplement oder Vorzeichen und Betrag dargestellt werden. Fast alle modernen Systeme verwenden das Zweierkomplement.

    – Keith Thompson

    30. November 2012 um 20:38 Uhr

  • @KeithThompson Wie entscheidet C99, dass vorzeichenbehaftete Ganzzahlen als Zweierkomplement oder als Einerkomplement dargestellt werden müssen? Ich meine, gibt es eine Möglichkeit, im Voraus zu wissen, wie meine vorzeichenbehaftete Ganzzahl dargestellt wird? Gibt es eine Möglichkeit, die Darstellung zu ändern, nachdem ein Wert zugewiesen wurde? Bitte teilen Sie mir auch mit, wenn dieser Kommentar zu weit gefasst ist und in eine neue Frage umgewandelt werden sollte.

    – Khaloymes

    1. Dezember 2012 um 9:45 Uhr

  • @Khaloymes: Ich bin mir nicht sicher, was du meinst. Es ist eine explizite Anforderung im Standard; siehe Abschnitt 6.2.6.2. Sie können die Art und Weise, wie Ihr System mit vorzeichenbehafteten Ganzzahlen arbeitet, nicht ändern; das wird im Allgemeinen durch die Hardware bestimmt. Sie können natürlich beliebige Bit-Manipulationen vornehmen, aber wenn Ihr System das Zweierkomplement verwendet, gibt es kaum einen Grund, eine andere Darstellung zu verwenden (es sei denn, Sie haben es mit einer extern auferlegten Datenanforderung zu tun).

    – Keith Thompson

    1. Dezember 2012 um 10:05 Uhr

  • @KeithThompson Das wollte ich wissen, ob ich an der Entscheidung beteiligt bin, wie eine vorzeichenbehaftete Ganzzahl dargestellt wird oder nicht. Ich schließe aus Ihrem Kommentar, der auf der Hardware basiert.

    – Khaloymes

    1. Dezember 2012 um 10:18 Uhr

  • @Khaloymes: Es liegt am Compiler-Implementierer, der die Wahl dokumentieren muss. Diese Entscheidung hängt mit ziemlicher Sicherheit davon ab, was die Hardware unterstützt (was heutzutage mit ziemlicher Sicherheit ein Zweierkomplement ist).

    – Keith Thompson

    1. Dezember 2012 um 10:22 Uhr

1412140cookie-checkWas passiert, wenn ich in C long int int zuweise?

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

Privacy policy