web-dev-qa-db-de.com

was ist der Grund für die explizite Angabe von L oder UL für lange Werte?

Aus einem Beispiel 

unsigned long x = 12345678UL

Wir haben immer gelernt, dass der Compiler im obigen Beispiel nur "long" sehen muss, um 4 Byte (in 32 Bit) des Speichers zu setzen. Die Frage ist, warum sollten wir L/UL auch in langen Konstanten verwenden, nachdem wir es als lang deklariert haben.

23
Shash

Wenn kein Suffix L oder UL verwendet wird, verwendet der Compiler den ersten Typ, der die Konstante aus einer Liste enthalten kann (siehe Details in C99-Standard, Abschnitt 6.4.4: 5. Für eine Dezimalkonstante ist die Liste int, long int, long long int).

Infolgedessen ist es in den meisten Fällen nicht erforderlich, das Suffix zu verwenden. Es ändert nichts an der Bedeutung des Programms. Dies ändert nichts an der Bedeutung Ihrer Beispielinitialisierung von x für die meisten Architekturen, obwohl dies der Fall wäre, wenn Sie eine Zahl gewählt hätten, die nicht als long long dargestellt werden könnte. Siehe auch die Antwort von Codebauer für ein Beispiel, in dem der Teil U des Suffixes erforderlich ist.


Es gibt einige Umstände, unter denen der Programmierer den Typ der Konstanten explizit festlegen möchte. Ein Beispiel ist die Verwendung einer variablen Funktion:

printf("%lld", 1LL); // correct, because 1LL has type long long
printf("%lld", 1);   // undefined behavior, because 1 has type int

Ein häufiger Grund für die Verwendung eines Suffix ist, dass das Ergebnis einer Berechnung nicht überläuft. Zwei Beispiele sind:

long x = 10000L * 4096L;
unsigned long long y = 1ULL << 36;

In beiden Beispielen hätten die Konstanten ohne Suffixe den Typ int, und die Berechnung würde als int erfolgen. In jedem Beispiel besteht die Gefahr eines Überlaufs. Die Verwendung der Suffixe bedeutet, dass die Berechnung stattdessen in einem größeren Typ ausgeführt wird, der einen ausreichenden Bereich für das Ergebnis aufweist.

Wie Lightness Races in Orbit sagt, steht das Suffix des Wurfes vor der Zuweisung. In den beiden obigen Beispielen reicht es nicht aus, x als long und y als unsigned long long zu deklarieren, um den Überlauf bei der Berechnung der ihnen zugewiesenen Ausdrücke zu verhindern.


Ein weiteres Beispiel ist der Vergleich x < 12U, bei dem die Variable x den Typ int hat. Ohne das Suffix U gibt der Compiler die Konstante 12 als int ein, und der Vergleich ist daher ein Vergleich der vorzeichenbehafteten Ints.

int x = -3;
printf("%d\n", x < 12); // prints 1 because it's true that -3 < 12

Mit dem Suffix U wird der Vergleich zu einem Vergleich vorzeichenloser Zeichen. "Übliche arithmetische Konvertierungen" bedeuten, dass -3 in ein großes vorzeichenloses int konvertiert wird:

printf("%d\n", x < 12U); // prints 0 because (unsigned int)-3 is large

Tatsächlich kann der Typ einer Konstante sogar das Ergebnis einer arithmetischen Berechnung ändern, wiederum aufgrund der Art und Weise, wie „gewöhnliche arithmetische Umrechnungen“ funktionieren.


Beachten Sie, dass die Liste der von C99 vorgeschlagenen Typen für Dezimalkonstanten nicht unsigned long long enthält. In C90 endete die Liste mit dem größten standardisierten Integer-Typ ohne Vorzeichen (der unsigned long war). Eine Folge war, dass die Bedeutung einiger Programme durch Hinzufügen des Standardtyps long long zu C99 geändert wurde: Dieselbe Konstante, die in C90 als unsigned long eingegeben wurde, konnte jetzt als signierter long long eingegeben werden. stattdessen. Ich glaube, dies ist der Grund, warum in C99 entschieden wurde, unsigned long long nicht in der Liste der Typen für Dezimalkonstanten zu haben. Ein Beispiel finden Sie in den Blogeinträgen this und this .

58
Pascal Cuoq

Weil numerische Literale typisch vom Typ int sind. Der UL/L teilt dem Compiler mit, dass sie nicht vom Typ int sind, z. 32 Bit int und 64 Bit lang 

long i = 0xffff;
long j = 0xffffUL;

Hier müssen die Werte rechts in vorzeichenbehaftete Longs umgewandelt werden (32bit -> 64bit)

  1. Das "0xffff", ein int, würde in eine long-Erweiterung mit Vorzeichen umgewandelt, was zu einem negativen Wert (0xffffffff) führt.
  2. Die "0xffffUL", eine vorzeichenlose long, wird in eine long konvertiert, was zu einem positiven Wert (0x0000ffff) führt.
8
codebauer

Die Frage ist, warum sollten wir L/UL auch in langen Konstanten verwenden, nachdem wir es als lang deklariert haben.

Weil es nicht "nach" ist; es ist "vor".

Zuerst haben Sie das Literal, dann es wird in den Typ der Variablen konvertiert, in die Sie es einpressen möchten.

Mit diesem Beitrag verwandt ist, warum eine u.

Ein Grund für u ist es, eine Ganzzahlkonstante größer als LLONG_MAX in Dezimalform zuzulassen.

// Likely to generate a warning.
unsigned long long limit63bit = 18446744073709551615`; // 2^64 - 1

// OK
unsigned long long limit63bit = 18446744073709551615u`;
0
chux