32-bit unsigned int Typecast



  • Hallo,
    ich habe gerade meine Probleme mit einem Typecast, der in C++ wohl offensichtlich anders abläuft als in ActionScript 3.0 (Flash).

    Code in Flash:

    var test:uint;
    test = Number("633876643524492195");
    
    trace(test);
    

    Ausgabe:
    3903961984

    Hier der Code in c++:

    unsigned int i = (int) 633876643524492195;
    TRACE("i is %u\r\n",i);
    

    Ausgabe:
    3903962019

    Ich will in c++ auf den gleichen Wert kommen wie in Flash.
    Ich freue mich über jede Hilfe!

    Michael



  • Die Zahl ist zu gross für den int , da werden Bits abgeschnitten. Du könntest es mit long long int versuchen, wenn dein Compiler das unterstützt - der Typ ist allerdings nicht im C++-Standard. Ansonsten kannst du zu einer externen Bibliothek greifen oder dir selbst was basteln.



  • Das ist schon richtig so. Den Code in Flash habe ich aus einer Anwendung, die ich nun nach c++ portieren will. Die Frage ist nun wie ich das gleiche Abschneide-Verhalten in c++ realisiere. Mich wundert außerdem, dass das Ergebnis gar nicht "Teilmenge" der ursprünglichen Zahl ist.



  • Es werden wie gesagt Bits, nicht Dezimalstellen abgeschnitten. Dadurch kann eine völlig andere Zahl herauskommen.

    Am einfachsten ist es wohl, die Zahl als String ( std::string ) zu speichern, dann kannst du führende Elemente entfernen.

    std::string num_str = "12345678901234567890";
    num_str.erase(0, anzahl_zu_loeschender_stellen);
    

    Für die Umwandlung zu int hilft dir std::stringstream im Header <sstream> :

    int integer;
    std::stringstream stream(num_str);
    num_str >> integer;
    

    Siehe auch www.cplusplus.com.



  • Zunächst einmal garantiert der C++ Standard hier kein bestimmtes Ergebnis. Das liegt daran, dass er nicht vorschreibt, was "unsigned int" und "int" genau ist, oder ob 64Bit-Werte überhaupt unterstützt werden.

    Dezimal: 633876643524492195
    Hex:        8CBFB72E8B1BBA3
    
    Dezimal:         3903962019  ("C++")
    Hex:               E8B1BBA3
    
    Dezimal:         3903961984  ("Flash")
    Hex:               E8B1BB80
                             ~~
    

    Beobachtungen:

    Die Zahl 633876643524492195 ist nicht mit 32 Bit darstellbar.

    Offensichtlich benutzt Dein C++ Compiler 32-Bit ints. (Das ist keine Seltenheit aber auch nicht selbstverständlich!)

    Wahrscheinlich konvertiert Flash die Zahl zu einer 32Bit Fließkommazahl (mit 24Bit-Mantisse) und anschließend zu einem Int. Dabei geht die Genauigkeit verloren. Wie man sieht, sind die letzten beiden Hex-Stellen unterschiedlich.

    Dein C++ Compiler unterstützt wahrscheinlich 64Bit-Konstanten. In der C++ Version ist keine Genauigkeit verloren gegangen.

    Siehe auch hier.

    Ich will in c++ auf den gleichen Wert kommen wie in Flash.
    Ich freue mich über jede Hilfe!

    Dann setze doch gleich die "richtige" Zahl ein.

    Ich kann die Ergebnisse nicht reproduzieren.

    #include <iostream>
    
    int main()
    {
      unsigned int z = 633876643524492195;
      std::cout << z << '\n';
    }
    

    liefert bei mir, mit dem G++ 4.4.1 kompiliert, die Zahl 4294967295 = 0xFFFFFFFF. Und eine Warnung bekomme ich auch dazu:

    Warnung: Große Ganzzahl implizit auf vorzeichenlosen Typen abgeschnitten
    

    Was ist passiert? Dem Compiler war die Konstante zu groß. Da ich im C++03-Modus kompiliert habe und long nicht groß genug für die Konstante ist, wurde die Konstante einfach durch 0xFFFFFFFF ersetzt. Wenn ich von der C99-Erweiterung "long long" gebrauch mache:

    #include <iostream>
    
    int main()
    {
      unsigned int z = 633876643524492195LL; // man achte auf den LL Suffix
      std::cout << z << '\n';
    }
    

    erhalte ich 3903962019 wie erwartet bei 32bit unsigned ints.

    Gruß,
    SP



  • Hi, vielen Dank für die ausführliche Antwort aber die Lösung ist das noch nicht, zumindest sehe ich sie nicht.

    Zum Hintergrund:
    Ein Flash-App kommuniziert mit einem Server. In jeder Antwort sendet der Server einen check-Value (z.B.: 633876643524492195), der im Applet in ein uint konvertiert und dann beim nächsten request wieder mitgesendet wird.

    Ich will die Kommunikation mit dem Server nun über eine c++ Anwendung realisieren also muss ich auch den Punkt mit der uint-konvertierung nachbilden.

    Ist aus deinem Post zu lesen, dass das gar nicht möglich sein soll?



  • Hecker.Michael schrieb:

    Hi, vielen Dank für die ausführliche Antwort aber die Lösung ist das noch nicht, zumindest sehe ich sie nicht.

    Eigentlich hat Sebastian dir das Problem bereits erklärt. Du musst deine lange Zahl zuerst in ein double quetschen, danach erst in ein int bzw. sicherheitshalber in ein __int32. Das scheint nämlich in der Actionscript-Variante zu passieren.

    #include <iostream>
    using namespace std;
    
    int main(void)
    {
        unsigned __int32 i;
        __int64 i64 = 633876643524492195;
    
        double d = i64;
        i = d;
    
        cout << i << endl;
        return 0;
    }
    

    Der Standard bleibt natürlich auf der Strecke.

    Welchen Datentyp hat denn dieses "check-Value" auf der Serverseite?



  • Das Problem ist, dass Du nicht genau weißt, was "Flash" da macht, und dass ohne Wissen darüber ein Protokoll "definiert" worden ist. Solltest Du die Möglichkeit haben, das Protokoll zu ändern, würde ich Dir empfehlen, das zu tun. Alles andere ist Pfusch. Wirklich! Wenn Du etwas in C++ schreiben willst, was genau das macht, was Flash macht, musst Du zunächst rauskriegen, was da genau passiert. Das von mir ist ja nur eine Vermutung.

    Du kannst es ja als Notlösung über Konvertierung nach double probieren:

    #include <iostream>
    #include <sstream>
    #include <string>
    
    int main()
    {
    	std::string zahl = "633876643524492195";
    	std::stringstream ss (zahl);
    	double x;
    	ss >> x;
    	unsigned u = x;
    	std::cout << u << '\n';
    }
    

    Es liefert bei mir die Ausgabe:

    3903961984
    

    Das ist aber -- wie gesagt -- implementierungsabhängig. Du solltest Dir schleunigst das verinnerlichen, was auf der Seite steht, die ich zum Thema C/C++ Datentypen verlinkt habe. Am besten baust Du mindestens noch etwas wie

    #include <climits>
    
    //...
    
    #if   UINT_MAX  == 4294967295
    typedef unsigned int   u32_t;
    #elif USHRT_MAX == 4294967295
    typedef unsigned short u32_t;
    #elif ULONG_MAX == 4294967295
    typedef unsigned long  u32_t;
    #else
    #error "Mich kannst Du so nicht kompilieren. Ich brauche 32-Bit Zahlen."
    #endif
    

    in eine Header-Datei ein und benutzt dann "u32_t" statt "unsigned int".

    Gruß,
    SP



  • Na also! Tausend Dank!
    Mir ist schon klar, dass das so nicht das gelbe vom Ei ist aber Zugang zum Server-Code kann ich nicht bekommen und so muss ich damit leben was ich habe.

    Ich danke euch!



  • Mitleid schrieb:

    Das scheint nämlich in der Actionscript-Variante zu passieren.

    Ja, so ist es. Sogar explizit:

    var test:uint;
    test = Number("633876643524492195");
    

    Number ist in AS3 quasi double. Schon ein komisches Konstrukt, das. Man könnte auch direkt in uint konvertieren.


Anmelden zum Antworten