Speichern von Zahlen groesser als 255 in mehreren Ints



  • hi!
    Ich habe ein (wahrscheinlich) echtes Anfängerproblem. Es geht dadrum:

    Ich hab ne zahl, z.B. 512 die in einer Int-Variable gespeichert ist.
    also: int x=512;

    jetzt ist 512 im Binärcode ja (Ich gehe von 16 bits aus, deshalb noch die ganzen nullen am anfang 🙂 ):
    0000.0010.0000.0000

    d.h., ich kann diese zahl folgender maßen in zwei bytes speichern:

    byte1 = 0000.0000
    byte2 = 0000.0010

    d.h. byte1=0 und byte2 = 2

    wenn ich dann byte1 und byte2 miteinander verkette, dann hab ich ja wieder die Anfängliche Binärschlange und weiß: die gespeicherte zahl war 512.

    Da ich momentan das BMP-Format auseinandernehme, wüsste ich gerne wie man Zahlen, die größer sind als 255 in mehrere bytes hintereinander schreibt.

    ich habe das schonmal folgendermaßen versucht:

    int x=512;
    char y[1];
    string zahl;
    
    zahl=itoa(x, zahl.c_str(), 2);
    
    if (zahl.length()<8)
    {
     y[0]= atoi(zahl);
     y[1]= 0;
    }
    if (zahl.length()>8)
    {
     y[0]= atoi(zahl.substr(zahl.length()-1, zahl.length()));
     y[1]= atoi(zahl.substr(0, zahl.lenght()-8));
    }
    

    aba irgendwie funtzte as nicht.

    mfg,
    chris90



  • Hi,

    vorerst:
    int ist üblicherweise = long und üblicherweise sind das 32 Bit und daher kannst du ein int in 4 chars aufteilen.
    Ich beschreibe es hier Mal für short (= 2 Chars, meistens = 16 Bit).
    du solltest hier Shiftoperatoren und co. verwenden.

    typedef std::pair<char, char> dchar;
    
    dchar short2dchar(int n)
    {
    char c1 = n & 255;
    char c2 = (n >> 8) & 255;
    return dchar(c1, c2);
    }
    

    Ungetestet, daher kann nich nicht garantieren, dass es so funktioniert.

    > und << verschieben alle Bits jeweils in eine Richtung (unschwer zu erkennen, welche), & verknüpft zwei Werte mit bitweisem Und (wenn a und b = 1, dann c = 1), | ist bitweises oder, ^ bitweises x-oder, ~ bitweises nicht.

    MfG Eisflamme



  • hoffe ich hab das hier richtig verstanden .... 😕

    naja, man kann aucn 4 + 3 mittles nem integral loesen 😃 Gluecklicherweisse macht das dann miest nen Processor 😃

    Du kannst dir aber auch die Haende mit pointer und Casts beschmutzen ... und nutzt das wissen, wie der comp die daten ablegt (achtung ! Intel und Motoral noatation beachten .... )

    unsigned short ishort = 0; // unser short was rauskommen soll 
    unsigned char * plowerchar = reinterpret_cast<unsigned char *>(&ishort);
    unsigned char * phigherchar = plowerchar + 1;
    
    // nun kannst einfach zuweisen .... 
    *plowerchar = 0;
    *phigherchar = 255;
    
    // und dein ishort sollte nun nen den entsprechenden Wert haben .... 
    _assert(ishort == 0xFF00);
    

    das ganze ist ziemlich unelegant .... und auch ned wirklich typsicher....
    Aber es gibt unter C ein nuetzliches construct, was sich fuer solche Zwecke hervorragend eignet !

    union
    {
        struct
        {
            unsigned char ilowerbyte;
            unsigned char ihigherbyte;
        } ibyte;
        unsigned short ishort;
    } data;
    
    // das macht die sache extrem bequem ! 
    data.ibyte.ilowerbyte = 0x00;
    data.ibyte.ihigherbyte = 0xFF;
    
    _assert(data.ishort == 0xFF00);
    

    Mit den richtigen datentypen kannst damit so fast jede Zahl zerhacken ...
    vorzeichenbehaftete zahlen sind etwas schwieriger .... Und du umgehst die Schiebeoperationen, die eigentlich weitaus mehr performance kosten duerften ...

    Ciao ...



  • das gibts nicht nur unter c 😉

    Da ich momentan das BMP-Format auseinandernehme, wüsste ich gerne wie man Zahlen, die größer sind als 255 in mehrere bytes hintereinander schreibt.

    Das BMP-Format beinhaltet keine Daten, die größer 255 sind, es sei denn die File Header. Wozu musst du das im Zusammenhang mit BMP machen?



  • @Randa
    Naja, da C immer noch bestandteil C++ ist ... sollte es logisch sein, dass das ganze unter C++ auch noch funzt.
    Glaub aber gelesen zu haben, das manche c++ compiler mit unnamed unions und structs probleme haben ...
    Unter VC++ gehts zumindest ....

    Ciao ...



  • vielleicht, aber unions werden immernoch unterstützt bzw. sind bestandteil von C++.



  • randa schrieb:

    Das BMP-Format beinhaltet keine Daten, die größer 255 sind, es sei denn die File Header. Wozu musst du das im Zusammenhang mit BMP machen?

    eben genau um den Header geht es.
    Ich schreibe jetzt selber BMP's und dazu benutze ich die ganzen fstream-funktionen.
    d.h:
    ofstream ofile1("hallo.bmp", ios::out);
    ofile1<<HEADER_TEIL1(z.B. int Breite);

    Das Problem: in bmp's ist jedes int auf vier chars verteilt, jedes short auf 2 und so weiter. wenn ich aber ein int in einen ofstream schreibe, dann wird es als string gespeichert und nicht als binärzahl.
    deswegen die zahl-zerhäckselung.

    @Mis2Com(Eisflamme): Vielen dank! In bitverschiebungen bin ich noch nicht so bewandert!
    Hier (falls es noch jemanden interessiert) die gegenfunktion:

    short int qchar2short (qchar qc1)
    {
    int i1 = qc1.bytes[0]; 
    int i2 = (qc1.bytes[1] << 8); 
    return i1+i2; 
    }
    

    mfg und vielen dank an alle,
    chris90



  • Lass die bitschieberei ... die bringt dir nix an der stelle ....

    was willst du genau ?

    du hasst nen schort ...

    denn schort streamst du in eine Textdatei ?

    was soll der short dir genau bringen .... angenommen dein short ist ishort = 65, was soll in der Textdatei stehen ???
    65
    oder
    A
    ???
    Ich vermute aber mal ganz stark, das deine bmp datei keine Textdatei sein soll ... also wuerde ich den stream mal als binaeren stream verwenden ....

    ios::binary Opens the file in binary mode (the default is text mode)

    Ciao ...



  • chris90 schrieb:

    Ich schreibe jetzt selber BMP's und dazu benutze ich die ganzen fstream-funktionen.
    d.h:
    ofstream ofile1("hallo.bmp", ios::out);
    ofile1<<HEADER_TEIL1(z.B. int Breite);

    😃 👍
    Du bist kreativ 😉
    die lösung des Problems:

    ofstream file ("xxx.bmp", std::ios::out);
    file.write (...);
    

    Edit: Also

    file.write (reinterpret_cast<char*> (data), sizeof (Data));
    


  • 1. @RHBaum:

    RHBaum schrieb:

    was soll der short dir genau bringen .... angenommen dein short ist ishort = 65, was soll in der Textdatei stehen ???
    65
    oder
    A
    ???

    DAS funktioniert ja auch. Wenn ich ein char vereinbare und ihm dann einen Integerwert gebe und das char in die file schreibe, speichert er ihn als binärwert. Aber das problem ist, dass ein short ja auch größer als 255 sein kann. Was mache ich z.B. wenn mein short 5000 ist? Dann brauche ich mindestens 2 character um es zu halten. Und in meinem fall geht es dadrum.

    Ich vermute aber mal ganz stark, das deine bmp datei keine Textdatei sein soll ... also wuerde ich den stream mal als binaeren stream verwenden ....
    Zitat:
    ios::binary Opens the file in binary mode (the default is text mode)

    Ich muss dich enttäuschen, aber ios::binary hat keinen Einfluss auf die Write-Funktion (hab's getestet).

    2. @randa:

    file.write (reinterpret_cast<char*> (data), sizeof (Data));
    

    Erste Frage: ist "data" gleich "Data"?
    Zweite Frage: Kann es sein, dass da noch irgendwo ein fehler drin ist? Bei mir gibt's einen laufzeit-absturz zu dieser stelle!!

    vielen dank, mfg,
    chris90

    PS:

    randa schrieb:

    Du bist kreativ 😉

    Klar: Was einem an Erfahrung fehlt, muss man mit verückten ideen ausgleichen 😃



  • ofstream myfile("xxx.bmp", std::ios::binary);
    
    short ishort = 257; 
    
    myfile << ishort;
    

    Glaub ned das der da ned binaer schreibt ....

    Glaub du hasst nen winzig kleines Verstaendniss Problem mit c++ streams 😃
    solltest dir echt mal naeher anschauen.
    Zum Beispiel sollte man bei outputstreams (ofstream) ned noch std::ios::out angeben muessen 🙂 Man kann natuerlich , aber ist wie mit fahradfahren und treten, wenns bergab geht.

    des weiteren:
    streams ueberschreiben die die << und >> operatoren, jeweils wie sie denken das es eben am wahrscheinlichsten ist, wie mans verwendet.

    Nen Textstream denkt immer fuer dich, dass wenn du nen char reinstreamst, dass es sich um einen Buchstaben handelt. myfile << static_cast<char>(65); wird er dir als A interpretieren und folgerichtig binaer 65 ins file schreiben.

    dagegen gibt es (noch) keine 32 bit zeichentypen, also wird er nen int/long immer als Zahl interpretieren ....
    also wenn dem das mit der Zeichenumwandlung eintrichtern willst, brauchst z.b den char nur auf nen long hochzucasten ....
    myfile << static_cast<long>(65); wird er dir also mit nem "65" im textfile quitieren. also

    ostream::write
    ostream& write( const char* pch, int nCount );

    ostream& write( const unsigned char* puch, int nCount );

    ostream& write( const signed char* psch, int nCount );

    Parameters

    pch, puch, psch

    A pointer to a character array.

    nCount

    The number of characters to be written.

    Remarks

    Inserts a specified number of bytes from a buffer into the stream. If the underlying file was opened in text mode, additional carriage return characters may be inserted. The write function is useful for binary stream output.

    wie du siehst, sollte der mode schon nen unterschied machen ....
    Da zeichenketten soweiso schon binaerformat sind, kannst die so nutzen ....

    Aber zugegeben, streams sind sehr "gewoehnugsbeduerftig". An vielen stellen setze ich auch noch die c-funktionen stattdessen ein, weil ich mir den aerger und das gecaste spare. Und printf & co sind manchmal echt pracktisch.

    Aber fuer dein Anwendungszweck sinds trotzdem gut geeignet, weil du die "probleme" relativ einfach umschiffen kannst.

    1. dein Header ist nen block aus Bytes. Behandle ihn doch auch so.

    Beispiel: dein "header" komplett ist 32 byte gross, und dein short (2byte) ist das 7. und 8. bit (also 6 und 7 auf mit Null begonnen).

    dann mach sowas

    char myheader[32] ; // gleich aufn stack anlegen, das ist schoen schnell 
    
    short & myshort(reinterpret_cast<short &>(myheader[6]));
    

    Nun hast deinen Header als Block vorliegen, und ne Referenz auf 2 byte in dem blosck als short, was willst mehr ....
    das ist userfreundlich und gleichzeitig performant ....

    das 7. und 8. byte kannst einfach ansprechen in dem auf die short ref zugreifst .... und raustreamen kannst das ganze in einem rutsch ....

    myshort = 258 // setzt das 6. byte in deinem header auf 2, und das 7. byte auf 1 (0x0102)
    
    ofstream file ("xxx.bmp", std::ios::binary);
    file << myheader; // streamt dir alles aufs mal raus ....
    

    schau dir zeiger und referenzen an, die sind fuer sowas, wenn mit bytebloecken arbeitest, eh unerlaesslich ...

    Ciao ...



  • chris90 schrieb:

    Erste Frage: ist "data" gleich "Data"?

    Ja, schreibfehler. Es muss einfach sizeof der zu schreibenden Variablen sein 😃

    Zweite Frage: Kann es sein, dass da noch irgendwo ein fehler drin ist? Bei mir gibt's einen laufzeit-absturz zu dieser stelle!!

    Hmm, bei reinterpret_cast musst du vorsichtig sein, wenn da irgendwas falsches gecastet wird, hast du ein Problem. Also ich habe ja bis jetzt noch kein Binärfile mit den streams geschrieben, nur Ascii. Aber schau dich mal bei google um, da findest du bestimmt irgendein Beispiel.
    Du solltest die Daten auch unbedingt einzeln in die Datei schreiben, wenn du einen Compiler hast, der dir die structs bzw. classes auf eine Größe optimiert, die ein vielfaches von zwei ist (wie z.B. VS). Da die File Header beide eine ungerade größe haben, würden sie beide "optimiert".

    Edit: Wie gesagt, ich weiß aus eigener erfahrung: Mit dem >> operator kriegst du nix vernünftiges aus ner Binärdatei raus.



  • wenn du einen Compiler hast, der dir die structs bzw. classes auf eine Größe optimiert

    Aehm wie meinst du das ?

    struct {
        char t1[27];
        char t2[122];
         } mystruct;
    
    std::cout << sizeof(mystruct);
    

    wuerde dir ned 149 zurueckgeben ?

    denk mal fuer pods optimiert der compiler sowieso ned ...
    Hatte mit dem VC++ eigentlich noch keine probleme mit ....

    Naja, und normalerweisse macht man sowas auch ned :

    MyClass m;
    
    ostream test;
    
    test.write(reinterpret_cast<char *>(&m),sizeof(MyClass ));
    

    sondern überlead den >> operator und schreibt die pods da einzeln ...

    und beim einlesen von pods aus nem binaerstream mittels >> hat ich auch noch keine probs ... was fuer eine STL-Impl verwendest du ?

    Ciao ...



  • ich glaub ich lag falsch, ein vielfaches von 32 Bits meinte ich, also dass es optimal für den Prozessor zu verdauen ist.

    Was das einlesen betrifft, so hatte ich schon ursprünglich vor, die File Header als ganze einzulesen per read, aber die Ergebnisse waren falsch.
    Mit Sicherheit kann ich dir sagen, dass das einlesen per >> bei mir mit der STL aus VC++ Net nicht funktioniert hat, aber ich wüsste nicht, warum meine STL anders sein sollte als andere. Du hast es doch nicht ernsthaft geschafft, Binärdateien mit >> auszulesen?



  • int Version;
    	bool bTemp;
    
    	ObjectLock(this);
    
    	if (bIsLoading)
    	{
    		stream >> Version;
    
    		switch(Version)
    		{
    		case 4:
    			stream >> m_byPass;
    		case 3:
    			stream >> m_bDisplayCumulativeMessages;
    		case 2:
    			stream >> m_nTag;
    			stream >> m_bOutputToTrace;
    		}
    
    		stream >> bTemp;
    		m_bPassThrough = bTemp ? 1 : 0;
    
    		UpdateView();
    	}
    
    	else
    	{
    		Version=4;
    		stream << Version;
    		stream << m_byPass;
    		stream << m_bDisplayCumulativeMessages;
    		stream << m_nTag;
    		stream << m_bOutputToTrace;
    
    		bTemp = (m_bPassThrough == 1);
    		stream << bTemp;
    	}
    

    Ist nen ausschnitt aus code, der bei uns sogar produktiv laeft ....
    ok, stream ist kein fstream direkt, sondern nur nen puffer, der aber irgendwann auch in nen file gelesen oder geschrieben wird ... theorethisch funkt das aber auch mit nem filestream direkt ....

    Ciao ....


Anmelden zum Antworten