lang lang in C / C ++

84

Ich versuche diesen Code auf dem C ++ - Compiler von GNU und kann sein Verhalten nicht verstehen:

#include <stdio.h>;

int main()
{
    int  num1 = 1000000000;
    long num2 = 1000000000;
    long long num3;
    //num3 = 100000000000;
    long long num4 = ~0;

    printf("%u %u %u", sizeof(num1), sizeof(num2), sizeof(num3));
    printf("%d %ld %lld %llu", num1, num2, num3, num4);
    return 0;
}

Wenn ich die kommentierte Zeile auskommentiere, wird der Code nicht kompiliert und gibt einen Fehler aus:

Fehler: Ganzzahlkonstante ist für langen Typ zu groß

Wenn der Code jedoch so kompiliert wird, wie er ist, und ausgeführt wird, werden Werte erzeugt, die viel größer als 10000000000 sind.

Warum?

sud03r
quelle
8
Vielleicht ist es jetzt zu spät, aber für zukünftige Leser empfehle ich die Verwendung <stdint.h>und Verwendung uint64_t. Um einen 64-Bit-Wert anzuzeigen,printf( "%" PRIu64 "\n", val);
enthusiasticgeek
@enthusiasticgeek <stdint.h>enthalten,uint64_t a = 0xffffffffffffff; printf( "%" PRIu64 "\n",a ); : error: expected ‘)’ before ‘PRIu64’ printf( "%" PRIu64 "\n",a ); :: warning: spurious trailing ‘%’ in format [-Wformat=] printf( "%" PRIu64 "\n",a );
Hirte

Antworten:

147

Die Buchstaben 100000000000 bilden eine Literal-Integer-Konstante, aber der Wert ist für den Typ zu groß int. Sie müssen ein Suffix verwenden, um den Typ des Literal zu ändern, d. H.

long long num3 = 100000000000LL;

Das Suffix LLmacht das Literal zum Typ long long. C ist nicht "klug" genug, um dies aus dem Typ auf der linken Seite zu schließen. Der Typ ist eine Eigenschaft des Literal selbst selbst und nicht des Kontexts, in dem er verwendet wird.

entspannen
quelle
47
Damals , als diese Antwort geschrieben wurde , war es wohl richtig, aber jetzt ist der C ++ Standard sagt , dass der Typ eines Ganzzahlliteral ohne Suffix ist die erste int, long intund long long intin dem sein Wert dargestellt werden. [C ++ §2.14.2 / 2] Daher muss das Suffix 'LL' jetzt nicht mehr zu einem ganzzahligen Literal hinzugefügt werden, das für andere Typen zu groß ist.
Bames53
8
Der Grund, warum dies zuvor ein Problem war, war nicht, dass C ++ nicht "intelligent" genug war, um den Literaltyp aus dem Typ der Variablen zu bestimmen, der zugewiesen wurde. Es wäre einfach gewesen, weil die Compiler-Erweiterung die erweiterte Ganzzahl nicht implementiert hat Geben Sie so ein, dass es mit der Standardsprache gut funktioniert. C ++ hat jetzt Regeln, nach denen sich alle erweiterten Ganzzahltypen besser in den Standard integrieren lassen: open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf
bames53
4
@unwind Ich denke, die Antwort sollte gemäß diesen Vorschlägen bearbeitet werden.
Antonio
26

Versuchen:

num3 = 100000000000LL;

Und übrigens, in C ++ ist dies eine Compiler-Erweiterung, der Standard definiert nicht lange lange, das ist Teil von C99.

Arkaitz Jimenez
quelle
11
Nun, C ++ 11 definiert jetzt lange lange
Mohamed El-Nakib
4

Es hängt davon ab, in welchem ​​Modus Sie kompilieren. long long ist nicht Teil des C ++ - Standards, sondern wird (normalerweise) nur als Erweiterung unterstützt. Dies wirkt sich auf die Art der Literale aus. Dezimale Ganzzahlliterale ohne Suffix sind immer vom Typ int, wenn int groß genug ist , um die Zahl darzustellen, andernfalls lang. Wenn die Anzahl für lange Zeit sogar zu groß ist, ist das Ergebnis implementierungsdefiniert (wahrscheinlich nur eine Anzahl vom Typ long int, die aus Gründen der Abwärtskompatibilität abgeschnitten wurde). In diesem Fall müssen Sie das LL-Suffix explizit verwenden, um die lange lange Erweiterung zu aktivieren (bei den meisten Compilern).

Die nächste C ++ - Version wird offiziell long long so unterstützen, dass Sie kein Suffix benötigen, es sei denn, Sie möchten ausdrücklich, dass der Typ des Literals mindestens lang ist. Wenn die Zahl nicht lange dargestellt werden kann, versucht der Compiler automatisch, long long auch ohne LL-Suffix zu verwenden. Ich glaube, das ist auch das Verhalten von C99.

sellibitze
quelle
1

Ihr Code wird hier gut kompiliert (auch wenn diese Zeile nicht kommentiert ist. Sie musste sie ändern

num3 = 100000000000000000000;

um die Warnung zu erhalten.

Omry Yadan
quelle
Welcher Compiler? In C ++ ist ein ganzzahliges Literal das kleinere von int oder long, in das es passt. In C99 ist es das kleinste von int, long, long long. Wenn Sie also lange auf C ++ als nicht standardmäßige Erweiterung umsteigen, hat Ihr Compiler möglicherweise auch die C99-Regeln für Literale übernommen.
Steve Jessop
gcc Version 4.3.2 (Debian 4.3.2-1.1) auf einem 64-Bit-Linux-System.
Omry Yadan
@SteveJessop Ein bisschen spät vielleicht: aber lang ist nicht unbedingt 64 Bit. Meistens ist es so, aber Sie haben keine Garantie, dass es überall sein wird. Die einzige Garantie, die Sie haben, ist, dass es mindestens so groß wie ein int ist, was wiederum mindestens so groß wie ein kurzes int ist, das wiederum mindestens so groß wie ein Zeichen ist. Schließlich wird char als groß genug definiert, um jedes Zeichen im Basiszeichensatz der Implementierung darzustellen (normalerweise 8 Bit).
Pauluss86
@ pauluss86: Ich habe nicht über Garantien gesprochen. Omry sagte, dass er gcc 4.3.2 auf einem 64-Bit-Debian-System verwendete. Ich bemerkte, dass dies erklärte, was er sah, da (ich wusste es zufällig aus allgemeinem Wissen) gcc auf solchen Systemen standardmäßig so konfiguriert ist, dass es 64 Bit longin Übereinstimmung mit dem LP64 ABI dieses Betriebssystems verwendet.
Steve Jessop
@SteveJessop Ich schlage nicht vor, dass Ihr Kommentar falsch ist! Nur darauf hinweisen, dass die Annahme, dass ein Long überall immer 64 Bit ist, was leider viele Leute denken, gefährlich ist.
Pauluss86