Was ist “int i = 1;Warum (i >= 60 * 60 * 1000 / 1 * 1000)” wahr?

Lesezeit: 5 Minuten

Benutzeravatar von Celebi
Celebi

Erstens ist es meine Schuld, zwei konstante Ausdrücke ohne Klammern zu definieren:

#define BIG_INTERVAL 60 * 60 * 1000
#define SMALL_INTERVAL 1 * 1000

int i = 1;

if (i >= BIG_INTERVAL / SMALL_INTERVAL - 1)
{
    printf("Oops!\n");
}

Das if Anweisung nach der Makroerweiterung ist if(i >= 60 * 60 * 1000 / 1 * 1000 - 1).

Das ist nicht meine Absicht. Aber ich finde etwas seltsam, wenn ich schreibe if (i >= 3600000000 - 1). Ist es falsch.

Welche Art ist 60 * 60 * 1000 / 1 * 1000 - 1 ? int?

  • Und hier haben wir den Grund, warum vernünftige Programmierer darauf verzichten #define für Konstanten.

    – jalf

    14. Juli 2011 um 6:20 Uhr

  • @jalf: Oder du könntest einfach daran denken, sie mit Klammern zu umgeben …

    – icktoofay

    14. Juli 2011 um 6:22 Uhr

  • Sie könnten. So wie es in Ordnung ist, sich selbst in den Fuß zu schießen, wenn Sie dafür sorgen, dass ein Arzt in der Nähe ist? Warum machen Sie es nicht einfach richtig und verwenden eine tatsächliche typisierte Konstante (sagen wir a static const intoder vielleicht eine Aufzählung)?

    – jalf

    14. Juli 2011 um 6:50 Uhr

  • @icktoofay: Das Problem ist, dass Klammern dieses spezielle Problem beheben, bis Sie es vergessen, und selbst wenn Sie dies nicht tun, werden Sie mit Makros um die Ecke auf ein anderes Problem stoßen. Es gibt einfach zu viele Dinge, die man im Auge behalten muss, wenn man Makros verwendet. Betrachten Sie dieses Makro, das in einem der Projekte enthalten war, an denen ich gearbeitet habe: #define for_all( iterator_t, it, container ) for ( iterator_t it = (container).begin(); it != (container).end(); ++it )das verwendet wird als: for_all( std::vector<int>::const_iterator, it, v ) std::cout << *it; einfach … oder?

    – David Rodríguez – Dribeas

    14. Juli 2011 um 7:28 Uhr

  • Habe die Frage auf “c” umgetaggt. Ihr Code ist NICHT c++; in C++ sollten Sie printf() und #define’s nicht verwenden

    – Andreas Bonini

    14. Juli 2011 um 13:16 Uhr

Alle Operatoren an ints Rückkehr int. Also ja, 60 * 60 * 1000 / 1 * 1000 - 1 ist ein int. Aber das erwartete Ergebnis von 3599999999 ist zu groß für eine intsodass der Ausdruck tatsächlich zu -694967297 ausgewertet wird (unter der Annahme von 32-Bit int und Zweierkomplement).

Dies passiert nicht mit einem Literal 3600000000 weil Integer-Literale größer als INT_MAX sind von einer Art, die kann den vollen Wert halten.

  • “ein Typ, der den vollen Wert enthalten kann” – WENN ein solcher Typ existiert. Es gibt keine Garantie für Literale, die überschreiten ULONG_MAX.

    – MSalter

    14. Juli 2011 um 8:56 Uhr

  • Integer-Überlauf (im Gegensatz zum Stapel) 🙂

    – Dunkler Stern1

    19. Juli 2011 um 18:39 Uhr

  • Eben 60 * 60 * 1000 kann zu groß für eine sein int; scheint meine Antwort.

    – Keith Thompson

    7. August 2011 um 0:09 Uhr

Benutzeravatar von Petar Ivanov
Petar Iwanow

60 * 60 * 1000 / 1 * 1000 – 1 = 3600000 * 1000 – 1, wodurch der int-Typ überläuft, sodass das Ergebnis alles sein kann (in Ihrem Fall ist es negativ, muss es aber nicht).

Um das zu erreichen, was Sie wollen, setzen Sie ( ):

#define BIG_INTERVAL (60 * 60 * 1000)
#define SMALL_INTERVAL (1 * 1000)

  • +1 für das Vorschlagen von Klammern – das erklärt das eigentliche Problem – obwohl das Vermeiden von Makros ein noch besserer Rat wäre. Dennoch lässt “überläuft den int-Typ, also ist er negativ” diesen Ton so klingen, als würde ersteres immer letzteres implizieren. Umständlich, aber formal ist es ein undefiniertes Verhalten für vorzeichenbehaftete ganzzahlige Typen und in der Praxis bedeutet es im Allgemeinen, dass Sie Müll erhalten, der positiv oder negativ sein kann … hier sind 3.600.000 * 1.000 zufällig <2 ^ 32, aber > 2 ^ 31, also ist es allgemein negativ Plattformen mit 32-Bit ints….

    – Toni Delroy

    14. Juli 2011 um 6:27 Uhr


Benutzeravatar von kazinix
kazinix

Hier meine Testergebnisse:

60 * 60 * 1000 / 1 * 1000 will result to -694967296

(60 * 60 * 1000) / (1*1000) will result to 3600

Es gibt ein Problem mit Ihrer Operation, dem Vorrang von Berechnungen.

Vielleicht möchten Sie einen Blick auf die Rangfolge der C++-Operatoren werfen http://msdn.microsoft.com/en-us/library/126fe14k%28v=vs.80%29.aspx. Sie werden den Grund finden, warum das Ergebnis -694967296 wurde, was meiner Meinung nach ein Effekt des Überlaufs ist.

  • @muntoo – Hier habe ich es erklärt.

    – Kazinix

    14. Juli 2011 um 6:40 Uhr

Wenn Sie einen Compiler verwenden, bei dem int 64 Bit ist, werden Sie feststellen, dass das Ergebnis Ihres Ausdrucks falsch ist. Wenn Sie einen Compiler verwenden, bei dem int 32 Bit oder 16 Bit ist, hat Ihr Ausdruck ein undefiniertes Verhalten, da der Überlauf von signierten ints nicht umlaufen muss. Wahrscheinlich hat sich deine gerade herumgewickelt, aber das muss nicht sein.

3600000000 ist eine Konstante, die zur Kompilierzeit sichtbar ist. Wenn also int nur 32 Bit beträgt, muss Ihr Compiler long long wählen (oder einfach long, wenn long 64 Bit beträgt). Ihr anderer Ausdruck wird also mit genügend Bits ausgewertet, um einen Überlauf zu vermeiden, und das Ergebnis ist korrekt.

Könnte sein, dass Sie die Größe eines int überlaufen, das 2147 m oder so signiert ist, was bedeutet, dass wenn Sie über die Darstellung gehen, wird dies negativ. Wie aus anderen Antworten hervorgeht, bewirkt die Division beim Erweitern nichts, also umgeben Sie die Makrodefinitionen mit Klammern

  • ca. 2147 Millionen , nicht 2,7 Millionen (unter der Annahme von 4 Byte Int)

    – Mitch Weizen

    14. Juli 2011 um 6:19 Uhr


  • Danke, ich sollte wirklich keine Fragen beantworten, wenn ich müde bin 😛

    – Jesus Ramos

    14. Juli 2011 um 6:20 Uhr

  • Es könnte von Interesse sein, dass dies wahrscheinlich für das OP geschieht, weil die interne Darstellung verwendet wird Zweierkomplementaber das Überlaufverhalten im Allgemeinen ist undefiniert.

    – Maxpm

    14. Juli 2011 um 6:21 Uhr


  • @Maxpm Sie haben völlig Recht, da einige Compiler den Überlauf konstanter Werte tatsächlich behandeln, indem sie ihn -1 oder einem anderen Wert zuweisen

    – Jesus Ramos

    14. Juli 2011 um 6:23 Uhr

Benutzeravatar von Jarod Elliott
Jarod Elliot

Sie verlassen höchstwahrscheinlich den gültigen Wertebereich für ein signed int – 3600000000 ist eine ziemlich große Zahl!

In diesem Fall wird der Wert zum kleinsten negativen Wert für den int-Datentyp.

Dies wird dazu führen, dass Ihre Aussage wahr ist.

  • ca. 2147 Millionen , nicht 2,7 Millionen (unter der Annahme von 4 Byte Int)

    – Mitch Weizen

    14. Juli 2011 um 6:19 Uhr


  • Danke, ich sollte wirklich keine Fragen beantworten, wenn ich müde bin 😛

    – Jesus Ramos

    14. Juli 2011 um 6:20 Uhr

  • Es könnte von Interesse sein, dass dies wahrscheinlich für das OP geschieht, weil die interne Darstellung verwendet wird Zweierkomplementaber das Überlaufverhalten im Allgemeinen ist undefiniert.

    – Maxpm

    14. Juli 2011 um 6:21 Uhr


  • @Maxpm Sie haben völlig Recht, da einige Compiler den Überlauf konstanter Werte tatsächlich behandeln, indem sie ihn -1 oder einem anderen Wert zuweisen

    – Jesus Ramos

    14. Juli 2011 um 6:23 Uhr

Benutzeravatar von Nicol Bolas
Nicol Bola

Jedes der Argumente dieses Ausdrucks ist eine ganze Zahl, also ist das Ergebnis eine ganze Zahl.

  • Ja, das sind ganze Zahlen. Genauer gesagt sind sie es ints. (Das Wort integer umfasst eine Reihe von Typen, von char bis zu long long; int' is a particular type, not *just* an abbreviation of Ganzzahl”.)

    – Keith Thompson

    7. August 2011 um 0:02 Uhr

1390580cookie-checkWas ist “int i = 1;Warum (i >= 60 * 60 * 1000 / 1 * 1000)” wahr?

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

Privacy policy