Schnelle Wandlung ASCII-HEX nach Binär



  • Ich muss auf einem Microcontroller eine ganze Menge ASCI-Hex Daten nach Binär wandeln.
    Leider dauert das alles noch zu lange. Mit Libary-Funktionen dauert es ewig.
    Ich habe nun Zeichen für Zeichen genommen, geguckt ob es zwischen 0-9 oder A-F liegt, entsprechend abgezogen und das High-Nibble um 4 nach links geschoben. Das geht schon viel schneller, ist aber immer noch langsam.

    Kennt jemand eine tolle und extrem schnelle Methode?

    Thx, Rafti



  • Arrays lassen sich meist für solche Berechnungen gebrauchen. Vor allem weil sie schnellen Zugriff bieten. Hier mal ein sehr plattformabhängiger Ansatz:

    #include <stdio.h>
    
    int ConvertHexCharToInt(char c)
    {
    	static const unsigned char HexCharToByte[] =
    	{
    		0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
    		0, 0, 0, 0, 0, 0, 0,
    		10, 11, 12, 13, 14, 15
    	};
    
    	return HexCharToByte[c - '0'];
    }
    
    int main()
    {
    	printf("%d\n", ConvertHexCharToInt('5'));
    	printf("%d\n", ConvertHexCharToInt('A'));
    	printf("%d\n", ConvertHexCharToInt('F'));
    
    	return 0;
    }
    

    Falls das überhaupt das ist, was du willst.

    Gruß
    Don06



  • nur noch die funktion weg machen und schneller geht's kaum.
    🙂



  • bei VC++ kann man mit __forceinline festlegen,
    dass eine Funktion unbedingt inline gehandhabt werden soll.

    wäre auch ne Lösung um die Funktion schneller zu machen.
    bei anderen Compilern dann nur inline, wobei da immer noch der Compiler entscheidet^^



  • DrakoXP schrieb:

    bei VC++ kann man mit __forceinline festlegen,
    dass eine Funktion unbedingt inline gehandhabt werden soll.

    wäre auch ne Lösung um die Funktion schneller zu machen.
    bei anderen Compilern dann nur inline, wobei da immer noch der Compiler entscheidet^^

    ...oder einfach als #define

    #define ConvertHexCharToInt(c) HexCharToByte[(c)-'0']
    

    🙂



  • und das Array global, oder was?

    da wäre das noch besser:

    #define HexCharToDWord(c) (unsigned long)(((c >= '0') && (c <= '9')) ? (c - '0') : ((((c >= 'A') && (c <= 'F')) ? (c - 'A') : ((((c >= 'a') && (c <= 'f')) ? (c - 'a') : (0xFFFFFFFF))))))
    

    sieht zwar bissel schrecklich aus^^
    aber es ist ein Define und braucht keine globalen Vars

    abtippen musst du es ja net, kannste ja direkt kopieren und einfügen^^

    außerdem funktioniert diese Version auch mit kleinbuchstaben, während die in den
    vorherigen Posts nur Großbuchstaben verarbeitet haben.



  • Der anderen Methode Kleinbuchstaben beizubringen ist trivial. Der Vorteil deines Dings (eine bessere Bezeichnung ist mir nicht eingefallen) ist, dass es range checks macht, welche bei der anderen Methode viel Speicher kosten würden.

    Und bei Konstanten spricht ja eigentlich auch nichts dagegen, dass sie "global" sind.



  • Tim schrieb:

    deines Dings (eine bessere Bezeichnung ist mir nicht eingefallen)

    naja, eigentlich würde man es als Makro bezeichnen xD



  • Das mit den Range-Checks wusste ich. Ich ließ sie weg, da es dem Threadsteller ja um Schnelligkeit ging. Und ein Zugriff auf ein Array ist nunmal schneller als bedingt ausgeführter Code (jedenfalls meistens). Ausserdem entnahm ich seinem Post, dass die Daten bereits in korrektem Format vorliegen. Eine Prüfung von Daten, die nicht überprüft werden müssen bzw. vorher schon geprüft wurden, ist ja unnötig.

    Gruß
    Don06



  • DrakoXP schrieb:

    da wäre das noch besser:

    #define HexCharToDWord(c) (unsigned long)(((c >= '0') && (c <= '9')) ? (c - '0') : ((((c >= 'A') && (c <= 'F')) ? (c - 'A') : ((((c >= 'a') && (c <= 'f')) ? (c - 'a') : (0xFFFFFFFF))))))
    

    lauter sprünge und vergleiche sind mit sicherheit viel langsamer als so'n simpler array-zugriff.
    🙂



  • Ich weiß ehrlich gesagt auch nicht, ob wir den OT richtig verstanden haben.
    Er will ja noch seine Nippel verschieben 😉

    EDIT: Mir fällt mal auf, dass der Thread im ANSI-C Forum is. Ich tausch mal std::cout mit printf aus.



  • Vielen Dank für die vielen Antworten!

    Und special thanks to Don06, das muss ich unbedingt ausprobieren, sieht vielversprechend aus.

    👍



  • Ich wusste doch, dass ich da vor kurzem mal was gefrickelt hab. Etwas langsamer als das von Don06 dafür weniger Speicherbedarf (auch bei groß-und kleinbuchstaben) und ebenfalls keine range-checks.

    unsigned char hex2bin(const unsigned char x){
        const unsigned char nums[2][10] = { { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9 },
                                   { 0, 10, 11, 12, 13, 14, 15,  0,  0,  0 } };
    
        return nums[x>>6][x&0xF];
    }
    


  • Wie wäre es mit einem einfachen switch-case ?

    int HexCharToInt( char* c )
    {
    	switch ( *c )
    	{
    		case '0':	return 0;
    			// ...
    		case 'F':	return 15;
    	}
    	return -1;
    }
    
    int main()
    {
    	char c = 'F';
    	printf( "%d", HexCharToInt( &c ) );
    	return 0;
    }
    


  • Die Frage ist, in wie weit der Kompiler das optimiert. Es geht ja um Schnelligkeit.

    Wieso übergibst du den Char als Pointer?



  • damit der char nicht extra noch einmal kopiert wird



  • Vergiss das mit dem Pointer und deklariere die Funktion als inline . Und schau dir unbedingt mal den Assembler Code bei eingeschalteter Optimierung (gcc -O3 -S) an.

    just my 2¢



  • Pedobear schrieb:

    Vergiss das mit dem Pointer und deklariere die Funktion als inline . Und schau dir unbedingt mal den Assembler Code bei eingeschalteter Optimierung (gcc -O3 -S) an.
    just my 2¢

    inline,
    ist das ansi c ?



  • wo sind wir denn hier schrieb:

    inline,
    ist das ansi c ?

    Ja, es ist ANSI C99.

    just my 2¢



  • Rafti schrieb:

    ... Kennt jemand eine tolle und extrem schnelle Methode?

    void Hex_Bin_64k(char* tab);
    
    int main() 
    { 
        // Das schnellste waere eine Tabelle,
        char tabelle[256*256] ; // fuer zweistellige Hexadezimalzahlen 
        char test;
        // bei der die hexadezimale Schreibweise als Index auf den Binärwert agiert.
        // Es ist eine Funktion zu schreiben, die die entsprechenden Binärwerte 
        // unter Beruecksichtigung von Gross- und Kleinschreibung in die Tabelle schreibt,
        // oder eine "globale" resp. "static" Tabelle als Ressource,
        // die die Binärwerte an richtiger Stelle enthaelt.
        Hex_Bin_64k (tabelle);
    
        test = tabelle['0a'] ;
    }
    
    void Hex_Bin_64k(char* tab)
    {
        unsigned char binaer = 0;
        unsigned short i = 0;
        char tmp1, tmp2;
    
        do
        {
              tmp1 = (char)i;
              tmp2 = (char)(i>>8);
    
              if (((tmp1 >= '0' &&  tmp1 <= '9') ||
                   (tmp1 >= 'A' &&   tmp1 <= 'F')) 
                  &&
                   ((tmp2 >= '0' &&  tmp2 <= '9') ||
                   (tmp2 >= 'A' &&  tmp2 <= 'F')))
              { 
                  tab[i] = binaer;
                  tab[i+32] = binaer; // Kleinschreibung beruecksichtigen
                  binaer++;
              }
             i++;
    
        }while (i);
    }
    

    MfG


Anmelden zum Antworten