-2147483648
-
groovemaster schrieb:
Na und? Auf einem 16-Bit System kann int halt auch nur 16 Bit breit sein.
ok, da würde das ganze natürlich nicht funktionieren
Die Frage ist ja, warum -2147483648 nicht als 32 Bit int vom Compiler akzeptiert wird.
Weil das ganze 2 Tokens sind: '-' '2147483648'. Letzteres ist keine als int darstellbare Zahl, also ist der Typ unsigned int.
-
Ich hab da weitere komische Sachen rausgefunden. In VC++ gibts ja den Typ signed __int64.
Mit der kleinstmöglichen Zahl bringt er mir da dieselbe Warnung:signed __int64 a = -9223372036854775808;
Für viele größere negative Zahlen kommt der Fehler nicht, aber komischerweise für den Bereich:
-4294967295 bis -2147483648
Für diese signed __int64-Zahlen bringt er die Warnung wieder!
Seltsam.
-
SG1 schrieb:
Weil das ganze 2 Tokens sind: '-' '2147483648'. Letzteres ist keine als int darstellbare Zahl, also ist der Typ unsigned int.
Was meinst du mit "keine als int darstellbare Zahl"???
Sie liegt nun mal im maximal möglichen Bereich.
Die Warnung bedeutet wohl eher, dass er eine solche negative Zahl nicht handeln kann, warum auch immer, und deshalb ihr Zweierkomplement verwendet, was ja auch wirklich bei Division und Modulo geschieht. printf() haben aber kein Problem damit.
-
JensE schrieb:
SG1 schrieb:
Weil das ganze 2 Tokens sind: '-' '2147483648'. Letzteres ist keine als int darstellbare Zahl, also ist der Typ unsigned int.
Was meinst du mit "keine als int darstellbare Zahl"???
Sie liegt nun mal im maximal möglichen Bereich.Nein, 2147483648 ist genau 1 zu gross. Erst DANACH wird das - angewendet.
-
Also hat es was damit zu tun, wie der Compiler den Code parst? Erzähl mir mehr darüber, ich will den genauen Grund erfahren!
-
SG1 schrieb:
Nein, 2147483648 ist genau 1 zu gross. Erst DANACH wird das - angewendet.
Es bimmelt langsam: 2147483648 ist ja um 1 größer als die größte signed long int Zahl. Das hättest du noch dazu sagen müssen, dann wäre es schneller gegangen
Allerdings versteh ich nicht, warum der Compiler so "dumm" ist. Und erklär mir einer das, was ich zwei Posts drüber zum besten gegeben habe, ich darf mich kurz mal selbst zitieren:
JensE schrieb:
Ich hab da weitere komische Sachen rausgefunden. In VC++ gibts ja den Typ signed __int64.
Mit der kleinstmöglichen Zahl bringt er mir da dieselbe Warnung:signed __int64 a = -9223372036854775808;
Für viele größere negative Zahlen kommt der Fehler nicht, aber komischerweise für den Bereich:
-4294967295 bis -2147483648
Für diese signed __int64-Zahlen bringt er die Warnung wieder!
Seltsam.
Das mit der kleinsten signed int-64 ist ja wieder verständlich, aber der Bereich -4294967295 bis -2147483648 ist verwirrend.
Kann ja nur daran liegen, dass der Compiler das eben als signed long int versucht zu interpretieren, und nicht als signed __int64.
-
SG1 schrieb:
Die Frage ist ja, warum -2147483648 nicht als 32 Bit int vom Compiler akzeptiert wird.
Weil das ganze 2 Tokens sind: '-' '2147483648'. Letzteres ist keine als int darstellbare Zahl, also ist der Typ unsigned int.
Nun, soweit waren wir ja schon. Das ist schon klar. Nur warum parst ein Compiler so dämlich. Wenn er mir schon signed Integer Typen anbietet, dann möchte ich doch bitte auch entsprechende Literale verwenden können. Ich sage ihm doch nicht, nehme 2147483648 und negiere, sondern nehme -2147483648. Verstehst du was ich meine?
-
Ich bin genau groovemasters Meinung!
Warum wird die Zahl -2147483648 überhaupt bereitgestellt, wenn man sie nicht wie alle anderen auch verwenden kann?
Das hat sicher einen guten Grund, es ist nur die Frage, welcher das ist.
Zumindest wird auch in limits.h jeweils die kleinste Zahl eines Bereiches geschickt umgangen, eben mit LONG_MIN.
-
Hab einen ähnlichen Artikel in der MSDN knowledge base darüber gefunden,
gebt einfach mal "PRB: Can't Set Certain DataTypes to Minimum Documented Value" bei "Suchen" ein und der Artikel müsste erscheinen.
da ist kurz beschrieben, wie MS Visual Basic mit den kleinsten Zahlen umgeht...
Es steht eben genau das drin, was SG1 über die Vorgehensweise des MSVC++ Compilers gesagt hat: Zuerst die Zahl, dann das Minus.
Schon komisch.
-
JensE schrieb:
Es steht eben genau das drin, was SG1 über die Vorgehensweise des MSVC++ Compilers gesagt hat: Zuerst die Zahl, dann das Minus.
Schon komisch.Nein. Der Compiler kann ja nicht wissen, was Du meinst. Die Mehrheitsmeinung der C-Gurus zu dem Thema war offenbar schwankend. In der aktuellen Norm, also C99, wird das Literal 2147483648 bei deiner Systemkonfiguration einem long long zugeschlagen, und dann das Minus darauf angewendet. Dann bekommt man eine negative Zahl vom Typ long long, die aber in einen long reinpasst. Nun zufrieden? Dann brauchst Du nur noch einen aktuellen Compiler (und den Code geringfügig anpassen).
Warum wird die Zahl -2147483648 überhaupt bereitgestellt, wenn man sie nicht wie alle anderen auch verwenden kann?
Sie wird haargenau wie alle anderen "bereitgestellt". -3 ist auch die Zahl 3, und darauf ein Minus angewendet. Die Sprachbeschreibung sieht negative Integerkonstanten nur über diesen Umweg vor. Da es aber normalerweise im Wertebereich eines long genau eine Zahl mehr im negativen, als im positiven Bereich gibt, hat man eben in C89 diesen etwas seltsamen Effekt, von denen C aber durchaus noch mehr zu bieten hat.
-
Daniel E. schrieb:
JensE schrieb:
Es steht eben genau das drin, was SG1 über die Vorgehensweise des MSVC++ Compilers gesagt hat: Zuerst die Zahl, dann das Minus.
Schon komisch.Nein.
Doch! Lies einfach mal an der angegebenen Stelle nach.
Daniel E. schrieb:
In der aktuellen Norm, also C99, wird das Literal 2147483648 bei deiner Systemkonfiguration einem long long zugeschlagen, und dann das Minus darauf angewendet. Dann bekommt man eine negative Zahl vom Typ long long, die aber in einen long reinpasst.
Soweit ist das klar.
Daniel E. schrieb:
Nun zufrieden? Dann brauchst Du nur noch einen aktuellen Compiler (und den Code geringfügig anpassen).
Also ist VC++ 6.0 + neuestes Service-Pack nicht aktuell? Und wie soll ich den Code geringfügig anpassen?
Und erklär mir das mal:
signed __int64 a = -2147483648; // hier kommt die oben genannte Warnung signed __int64 b = -2147483647; // hier nicht mehr signed __int64 c = -4294967295; // hier kommt auch die Warnung signed __int64 d = -4294967296; // hier kommt sie nicht mehr
Soll heißen alle Zahlen zwischen -2147483648 und -4294967295 behandelt mein Compiler immer als positiv.
Grüße
Jens
-
JensE schrieb:
Daniel E. schrieb:
JensE schrieb:
Es steht eben genau das drin, was SG1 über die Vorgehensweise des MSVC++ Compilers gesagt hat: Zuerst die Zahl, dann das Minus.
Schon komisch.Nein.
Doch! Lies einfach mal an der angegebenen Stelle nach.
Ich habe den Thread gelesen und sogar schon auf der ersten Seite die Erkläung gepostet. Komisch ist an diesem Verhalten nichts.
Daniel E. schrieb:
Nun zufrieden? Dann brauchst Du nur noch einen aktuellen Compiler (und den Code geringfügig anpassen).
Also ist VC++ 6.0 + neuestes Service-Pack nicht aktuell? Und wie soll ich den Code geringfügig anpassen?
VC 6 kommt aus der Steinzeit (1995 oder so, nicht?). Ein Servicepack macht meiner Erinnerung nach die gröbsten Bugs raus und bringt vielleicht ein paar kleine Features mit. C99 verlangt aber normalerweise einen vollständig reimplementierten Compiler.
Anpassen müßtest Du deine printf-Aufrufe, weil Du einen long long anders ausgeben mußt, als einen int, was auf der ersten Blick einsichtig sein sollte.
Und erklär mir das mal:
signed __int64 c = -4294967295; // hier kommt auch die Warnung signed __int64 d = -4294967296; // hier kommt sie nicht mehr
Soll heißen alle Zahlen zwischen -2147483648 und -4294967295 behandelt mein Compiler immer als positiv.
4294967296 passt nicht mehr in einen unsigned long, also versucht der Compiler gar nicht erst, ihn da reinzustecken und warnt auch nicht. Wo ist das Problem?
-
Das Problem ist, dass z.B. die Zahl -4294967295 als 4294967295 behandelt wird.
Wenn ich beispielsweise schreibe -4294967295 / 10, kommt 0 raus (weil er diese Zahl als 1 oder so interpretiert), und nicht -429496729.
Also wie bei der kleinsten long Zahl.
Nur sehe ich nicht ein, warum er das hier macht, das ist doch nun echt absolut schwachsinnig: Wenn ich ihm nun sag, ich verwende signed __int64, warum will er die Zahl nicht so behandeln, wie ich sie hinschreib?Ist das für dich also vollkommen normal? Machst du dann in Code, der signed __int64 verwendet, sowas:
if (a < -2147483647 && a > -4294967296) b = - (a / 10); else b = a / 10;
-
Daniel E. schrieb:
Daniel E. schrieb:
Nun zufrieden? Dann brauchst Du nur noch einen aktuellen Compiler (und den Code geringfügig anpassen).
Also ist VC++ 6.0 + neuestes Service-Pack nicht aktuell? Und wie soll ich den Code geringfügig anpassen?
VC 6 kommt aus der Steinzeit (1995 oder so, nicht?).
Nee, der MSC 6 ist von 1998. Ist aber trotzdem mehr als alt und der aktuelle Standard war damals auch noch nicht fix. Aktuelle ist der MSC 8.
JensE schrieb:
Das Problem ist, dass z.B. die Zahl -4294967295 als 4294967295 behandelt wird.
Wenn ich beispielsweise schreibe -4294967295 / 10, kommt 0 raus (weil er diese Zahl als 1 oder so interpretiert), und nicht -429496729.
Du hast recht, diese wird auch als 1 interpretiert. Das ist aber auch logisch, da Integer Literale ohne Spezifizierung imer vom Typ int sind. Willst du etwas anderes, musst du entsprechende Suffixe verwenden, zB
long long a = -4294967295ll / 10;
Da der MSC 6 aber wie gesagt schon ziemlich alt ist, unterstützt der keinen Typ long long (nur __int64) und vermutlich auch kein ll Suffix (aber wahrscheinlich etwas vergleichbares).
-
Anscheinend gibt es keinen solchen Suffix für MSVC++ 6.0.
Gut, da ich Methoden haben, die signed __int64 übergeben bekommen, muss ich also quasi dem Anwender sagen:
"Übergib Konstanten immer mit dem entsprechenden Suffix, sonst werden sie von bestimmten Compilern eventuell anders interpretiert."
Wenn ich mir dann irgendwann mal einen neueren Compiler zulege, nehm ich ja dann sowieso den plattformunabhängigen Typ long long.
Also ich nehme aus dieser Diskussion mit:
- Alle Zahlen sind für den Compiler erstmal ints, wenn sie kleiner gleich 2^32 - 1 sind, egal, ob da noch ein Minus davor steht
- Wenn aber ein Minus davorsteht, sind die Zahlen von -2147483648 bis -4294967295 zu klein, um als signed int angesehen zu werden, also nimmt er sie positiv
- Um das zu vermeiden, müsste man einen Suffix verwenden, wenn es ihn gäbe
- Alle Zahlen größer als 4294967295 werden eben immer als __int64 genommenSo in etwa habe ich das jetzt alles verstanden. Korrigiert mich bitte, wenn ich da falsch liege.
Warum das so geregelt wurde, ist mir aber noch nicht so richtig klar, und warum das nirgendswo ordentlich dokumentiert wurde, auch nicht.
-
JensE schrieb:
- Um das zu vermeiden, müsste man einen Suffix verwenden, wenn es ihn gäbe
Diese Suffixe gibt es.
u U - unsigned
l L - long
ll LL - long longSo werden sie vom Standard definiert. Lediglich ältere Compiler werden wohl ll LL nicht unterstützen.
JensE schrieb:
- Alle Zahlen größer als 4294967295 werden eben immer als __int64 genommen
Diese Regelung ist mir ehrlich gesagt unbekannt.
-
groovemaster schrieb:
Diese Suffixe gibt es.
u U - unsigned
l L - long
ll LL - long longSo werden sie vom Standard definiert. Lediglich ältere Compiler werden wohl ll LL nicht unterstützen.
Ja, bei meinem VC++ 6.0 gibt es ll und LL nicht. Auch für __int64 gibt es wohlgemerkt keinen microsoft-spezifischen Suffix.
groovemaster schrieb:
JensE schrieb:
- Alle Zahlen größer als 4294967295 werden eben immer als __int64 genommen
Diese Regelung ist mir ehrlich gesagt unbekannt.
Naja, ich meine damit: Wie parst er denn beispielsweise diese Zeile?
signed int __64 = -42949672950;
Er wird ja -wie von anderen bereits gesagt wurde - zuerst die Zahl betrachten. Und jetzt merkt er: AHA, größer als LONG_MAX. Also denkt er sich, der Suffix (wenn es einen gäbe) ist hier überflüssig, und keine Warnung kommt, er nimmt die Zahl so, wie sie ist.
-
JensE schrieb:
groovemaster schrieb:
JensE schrieb:
- Alle Zahlen größer als 4294967295 werden eben immer als __int64 genommen
Diese Regelung ist mir ehrlich gesagt unbekannt.
Naja, ich meine damit: Wie parst er denn beispielsweise diese Zeile?
signed int __64 = -42949672950;
Er wird ja -wie von anderen bereits gesagt wurde - zuerst die Zahl betrachten. Und jetzt merkt er: AHA, größer als LONG_MAX. Also denkt er sich, der Suffix (wenn es einen gäbe) ist hier überflüssig, und keine Warnung kommt, er nimmt die Zahl so, wie sie ist.
__int64 ist kein Teil von C, d.h. der Compiler kann machen, was er will.
In C99 mit long long arbeitend, läßt ein Ausdruck wie 9223372036854775808ll (= -LLONG_MIN) den Typ long long überlaufen, also hat man es formal mit undefiniertem Verhalten zu tun. Bei handelsüblichen Rechnern, die Zahlen im Zweierkomplement darstellen, kommt also bei -92...8ll aber überraschenderweise wirklich LLONG_MIN heraus. Eine Garantie dafür gibt es aber nicht, wenn ich nichts übersehen habe.
-
Okay,
vielen Dank für die umfangreichen Antworten, hat mich wirklich weiter gebracht.