Advanced ByteToInt



  • Hallo, (ja, ich bins mal wieder^^)

    Es geht darum, dass ich nen riesigen Array mit
    Bytes habe (meiste davon is trash), nun habe ich eine
    Stelle lokalisiert an der sich eine Zahl befindet die ich brauche,
    das Problem ist nur, sie ist 2 bytes lang.
    Wenn sie nur ein byte lang wäre hätte ich es so gemacht

    (int)myData[1234]
    

    aber ich muss iergendwie hinkriegen,
    dass es die zwei Ziffern
    zb:

    17 E0
    

    als eine Zahl ansieht (6112)

    Ich hoffe ihr versteht was ich meine.

    Grüße



  • Hallo

    Die einzelnen Bytes als unsigned char auslesen und mit Bitshifting in einen Integer zusammensetzen.

    unsigned char a = 10;
    unsigned char b = 20;
    unsigned int c = (unsigned int(a) << 8) + b;
    

    bis bald
    akari



  • akari schrieb:

    Hallo

    Die einzelnen Bytes als unsigned char auslesen und mit Bitshifting in einen Integer zusammensetzen.

    unsigned char a = 10;
    unsigned char b = 20;
    unsigned int c = (unsigned int(a) << 8) + b;
    

    bis bald
    akari

    Respekt, ich wusste noch nicht dass sowas existiert, kannst du mir bitte erklären wie die 8 zustande kommt?

    Danke schonmal,
    es funktioniert einwandfrei



  • Ein Byte hat 8 Bit.



  • Braunstein schrieb:

    Ein Byte hat 8 Bit.

    Nicht unbedingt...
    Etwas genauer also: 😉

    unsigned char a = 10;
    unsigned char b = 20;
    unsigned int c = ( a << CHAR_BIT ) | b;
    


  • Jetzt ist es portabel 🙂



  • gibt es systeme, für die c++ compiler existieren, die nicht 8 bit pro byte nutzen? von irgendwelchen speziallösungen im embedded bereich mal abgesehen.



  • thordk schrieb:

    gibt es systeme, für die c++ compiler existieren, die nicht 8 bit pro byte nutzen? von irgendwelchen speziallösungen im embedded bereich mal abgesehen.

    Ya, durchaus: http://www.parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.4

    Machs so:

    template< unsigned bits >
    class CharToUInt
    {
    	typedef TYPE_LIST_4( unsigned char, unsigned short, unsigned int, unsigned long ) unsigned_integrals;
    
    public:
    	typedef typename TL::TypeBySize< unsigned_integrals, bits >::Type IntType;
    
    	static IntType Convert( char c1, char c2 )
    	{
    		assert( ( sizeof( char ) * 2 ) <= sizeof( IntType ) );
    		return static_cast< IntType >( ( c1 << CHAR_BIT ) | c2 );
    	}
    
    	static IntType Convert( char c1, char c2, char c3 )
    	{
    		assert( ( sizeof( char ) * 3 ) <= sizeof( IntType ) );
    		return static_cast< IntType >( ( c1 << CHAR_BIT * 2 ) | ( c2 << CHAR_BIT ) | c3 );
    	}
    
    	static IntType Convert( char c1, char c2, char c3, char c4 )
    	{
    		assert( ( sizeof( char ) * 4 ) <= sizeof( IntType ) );
    		return static_cast< IntType >( ( c1 << CHAR_BIT * 3 ) | ( c2 << CHAR_BIT * 2 ) | ( c3 << CHAR_BIT ) | c4 );
    	}
    };
    

    Das TYPE_LIST_X Macro, sowie die TypeList Templates sind aus Andrei Alexandrescu's Modern C++ Design geliehen! 😉 Folgende Funktionalität hab ich dazu gebastelt:

    template< typename TList, unsigned int bits >
    struct TypeBySize;
    
    template< unsigned int bits >
    struct TypeBySize< NullType, bits >
    {
    	typedef void Type;
    };
    
    template< typename T, typename U, unsigned int bits >
    struct TypeBySize< TypeList< T, U >, bits >
    {
    	typedef typename Select< ( ( sizeof( T ) * CHAR_BIT ) == bits ), T, typename TypeBySize< U, bits >::Type >::Result Type;
    };
    

    Verwenden tust du das so:

    unsigned char a = 10;
    unsigned char b = 20;
    unsigned char c = 30;
    unsigned int d = CharToUInt< 32 >::Convert( a, b, c );
    

    Und das ganze jetzt bitte nicht zu ernst nehmen! 😉 *hust*



  • Ich habe auch immer wieder das Bedürfnis gehabt, meinem Rechner "auf die Finger" zu schauen...(oder viel mehr dem Compiler) 😉 ... und habe einige Lösungen ausprobiert:

    1.) das "Modulo-Vervahren":
    Es funktioniert allerdings nur bei Ganzzahlen-Typen (int, long, länger, ...)
    Das Prinzip beruht darauf, daß bei Division durch 2 nur ein Rest (Modulo) bleibt, wenn das niederwertigste Bit =1 ist.
    Funktion IntToBin:

    String bin;
    long eingabe=25;
    ...
    while(eingabe>0)
       {
       if(eingabe%2==0)
          bin+="0";
       else
          bin+="1";
       eingabe/=2;
       }
    bin=strrev(bin.c_str());
    

    2.) Das Shift-Verfahren:
    Wie Akari schon andeutete, läßt sich die Position, an der gelesen wird auch durch Shiften ermitteln:

    //Parameter:
    // str: char-String für's Ergebnis
    //      char str[9];  so sollte 'str' definiert sein (...)
    // bin: enthält das zu wandelnde Zeichen.
    
    char *bintostr(char *str,char bin)
    {
        for (int i=0; i<8; i++)
            if ((bin|(~(1<<(7-i))))==(-1))
                str[i]='1';
              else
                str[i]='0';
        str[8]='\0';
        return str;
    }
    

    3.) Binär-Logik:
    Ich hatte das Ziel ganze Klassen (wenn's sein muß) abbilden zu können, daher benötigte ich etwas *wirklich* generisches, daß nicht auf einen Typ beschränkt ist.
    Außerdem durfte es intern keine Variable benötigen, die genauso groß wie der zu wandelnde Speicherbereich (!!) ist, daher rastert meine Lösung den gesamten Speicherblock Byteweise ab.

    Das Verfahren ist einfach:

    01010010 . . (beliebige Quell-Daten)
    00000100 & . Es soll an 3. Stelle gelesen weden
    00000000 . . Ergebnis: false.

    Gegenprobe:
    01010010 . . (beliebige Quell-Daten)
    00000010 & . Es soll an 2. Stelle gelesen weden
    00000010 . . Ergebnis: true.

    Man kann aber auch [ Data | ~(2 hoch Stelle) ] rechnen ...

    Als Funktions-Template sieht das dann so aus:

    template <typename T> UnicodeString ToBin (T *Quelle ){
    	UnicodeString str;
    	if(Quelle){
    		for(char* ende = reinterpret_cast<char*>(Quelle)+sizeof(T)-1;Quelle <= ende; ende--){
    			str+=((*ende)& 128)?'1':'0';
    			str+=((*ende)& 64)?'1':'0';
    			str+=((*ende)& 32)?'1':'0';
    			str+=((*ende)& 16)?'1':'0';
    			str+='.';
     			str+=((*ende)& 8)?'1':'0';
     			str+=((*ende)& 4)?'1':'0';
    			str+=((*ende)& 2)?'1':'0';
    			str+=((*ende)& 1)?'1':'0';
    			str+=' ';
    		}
    	}
    	return str;
    }
    
    // Bsp.:
    void main(void){
    
            unsigned __int64 test_1=3141592653589793238;
            unsigned __int32 test_2=3141592653589793238;
            unsigned __int16 test_3=3141592653589793238;
            TmyClass *test_4 = new TmyClass("Lorem Ipsum");
    
            ShowMessage("Test: Binäre Ausgabe\n\nTest 1\t= "+ToBin(&test_1)
                    +"\nTest 2\t= "+ToBin(&test_2)
                    +"\nTest 3\t= "+ToBin(&test_3)
                    +"\nTest 4\t= "+ToBin( test_4)); // test_4 ohne '&' - es ist ja schon ein Zeiger
    
            delete test_4;
    }
    

    Und weil der Mensch nie glücklich ist, habe ich noch eine zweite Version,
    mit der man beliebige Speicherbereiche darstellen kann; 'Quelle' gibt hier nur den Bereichsbeginn an:

    template <typename T> UnicodeString ToBin (T *Quelle, size_t len){
    	 UnicodeString str;
     	if(Quelle){
    		for(char* ende = reinterpret_cast<char*>(Quelle)+len-1;Quelle <= ende; ende--){
    			str+=((*ende)& 128)?'1':'0';
    			str+=((*ende)& 64)?'1':'0';
    			str+=((*ende)& 32)?'1':'0';
    			str+=((*ende)& 16)?'1':'0';
    			str+='.';
    			str+=((*ende)& 8)?'1':'0';
     			str+=((*ende)& 4)?'1':'0';
     			str+=((*ende)& 2)?'1':'0';
     			str+=((*ende)& 1)?'1':'0';
     			str+=' ';
    		 }
            }
    	return str;
    }
    
    // Bsp.:
    void main(void){
    
            TmyClass *test_1 = new TmyClass("Lorem Ipsum");
    
            ShowMessage("Test: Binäre Ausgabe\n\nTest 1\t= "+ToBin( test_1, sizeof(TmyClass))
                    +"\nTest 2\t= "+ToBin( test_1, 50)); // was immer auch dabei herauskommen mag ;)
    
            delete test_1;
    }
    

    Formatierung: rechts steht das niederwertigste Bit; die Bytes durch ein Leerzeichen, und die Nibbles durch ein Punkt getrennt (Sieht Hexeditor-mäßig aus, ist aber Geschmackssache).

    Der Speicherbereich, auf den 'Quelle' zeigt, wird Byteweise abgelesen.
    In der ersten Version wird als Längeninformation die Typengröße ( sizeof(T) ) verwendet, in der Zweiten stellt 'Quelle' nur die Startadresse dar und 'len' gibt die Größe des zu lesenden Bereiches an - damit ließen sich dann auch beliebige Speicherausschnitte ausgeben.

    --> Das ist Borlad-C++; UnicodeString kann natürlich durch einen anderen Typ ersetzt werden.
    --> Mit der Aufzählung der Stellenweisen Auswertung wollte ich mir eine weitere Schleife mit einer weiteren Variable sparen ... Also "Auslagerung von Rechenzeit auf Programierzeit", oder so in der Art. Mit "Register-Aritmetik" ginge das zwar noch besser, aber ich spreche leider kein Assembler...

    So, jetzt sollten die meisten Anwendungen doch Abgefrühstückt sein, oder?

    Viel spaß damit!

    Und wie immer: Wer einen Fehler findet, darf ihn behalten! 😉


Anmelden zum Antworten