Problem mit strtok()



  • Guten Abend zusammen,

    ich bräuchte mal eure Hilfe.
    Und zwar bin ich gerade dabei einen Mikrocontroller zu programmieren, welcher eine Antwortzeichenfolge eines Servers auswertet. Diese sieht so aus:
    *112923450*20*21690**642867104857625465000000*0

    Die beiden "**" sind kein Tippfehler.

    Die Zeichenfolge liegt als String vor und soll nun auf die einzelnen Zahlenblöcke aufgeteilt werden. Diese sollen in einzelne chars oder ein String-Array kommen, das ist im Grunde egal.

    Mein Ansatz war nun folgender:

    String werte[10];
    (...)
    Ausgabe.toCharArray(charBuf, 50);
    
            char *strpart = strtok(charBuf, "*");
             int c=0; 
    
            while(strpart!=NULL) {
              for(int d=0; &strpart[d]!=0; d++) {
                werte[c] += &strpart[d];
              }
              c++;
              strpart=strtok(NULL, "*");
            }
    

    im String "Ausgabe" befindet sich die Ausgangszahlenfolge.

    Der Compiler läuft anstandslos durch, der Mikrocontroller resettet sich jedoch immer kurz nach Verbindungsaufbau, was bedeutet, dass da irgendwo noch ein Haken drin ist.
    Kann mir jemand den Fehler nennen, oder sogar eine elegantere/bessere Möglichkeit, mein Vorhaben zu realisieren?

    Vielen Dank schonmal, Gruß
    Julian



  • Willst du C oder C++ machen? Kann man heute für uC schon C++ einsetzten?


  • Mod

    Was ist hier denn ein "String"?

    Was mir jedenfalls auffällt ist, dass du da irgendwie das Ergebnis eines Adressoperators so benutzt, als wäre es semantisch etwas anderes (keine Ahnung, was du dir dabei gedacht hast): &strpart[d] .
    Lass mich raten: Irgendetwas hat nicht compiliert und du hast so lange zufällig Zeichen im Code eingefügt, bis es übersetzte.



  • &strpart[]
    

    ist falsch und möchte (wenn überhaupt sinnvoll) gerne

    strpart[]
    

    heißen.
    Nimm sscanf, bei konstanter Zahl von auszuwertenden Teilen im Ausgangsstring sehr kurz:

    char s[5][100];
    if( 5==sscanf("*112923450*20*21690**642867104857625465000000*0","*%[^*]*%[^*]*%[^*]**%[^*]*%[^*]",s[0],s[1],s[2],s[3],s[4]) )
      puts("OK");
    else
      puts("Fehler bei der Auswertung");
    

    sscanf zerstört im Gegensatz zu strtok den Ausgangsstring nicht, der darf also auch const sein.



  • Also erstmal vielen Dank an Wutz, der den Fehler ausfindig gemacht hat (ich bin heute irgendwie etwas neben der Spur, peinlicher Fehler...)!
    Die Konstruktion mit strtok() funktioniert jetzt, ich werde aber sscanf() verwenden - nochmals Danke für Tip und Erklärung.

    SeppJ schrieb:

    Lass mich raten: Irgendetwas hat nicht compiliert und du hast so lange zufällig Zeichen im Code eingefügt, bis es übersetzte.

    Leider falsch geraten, s.o.
    Mir ist schon klar, dass der Dereferenzerierungsoperator sinnvoller gewesen wäre, wenn überhaupt, wirklich keine Ahnung, was ich mir dabei gedacht hatte...

    out schrieb:

    Willst du C oder C++ machen? Kann man heute für uC schon C++ einsetzten?

    Und nochmal sorry, es handelt sich um schnödes C...

    Meinen nächsten Beitrag verfasse ich mit klarem Kopf, versprochen! 😉



  • Was für ein uC ist das, für den du da codest? Wenn's um das Standard-AVR-Zeug geht, ist sscanf ziemlich bloatig (auf einen Schlag der halbe Progmem weg), und

    char s[5][100];
    

    kann man aus Speichergründen gleich vergessen (zumal du da ja Kopien ziehst). Auf uCs sind eierlegende Wollmilchsaufunktionen fast nie eine gute Idee. Ich würd bei strtok bleiben (und wenn mir der PM ausgeht, ne Minimallösung von Hand basteln).



  • Also ich persönlich würde, gerade wenn das auf nem (vermutlich nicht sehr fett mit RAM und CPU Leistung ausgestatteten) Mikrocontroller laufen soll, einfach eine Schleife machen und die Teilstrings selbst auseinanderklauben.

    sprintf ist halt nicht gerade das schnellste Werkzeug unter der Sonne, und es zieht auch oft nen grossen Teil der Runtime-Library mit rein den man sonst vielleicht gar nicht braucht (heisst: das Image wird grösser).



  • Und für deine for-Schleife kannst du strncat verwenden.



  • hustbaer schrieb:

    vermutlich nicht sehr fett mit RAM und CPU Leistung ausgestatteten

    Ich hab nen Robby mit Mikrocontroller. 2000 (!!!) Byte SRAM, 8Mhz CPU... char[5][100] ist da wohl schon vielleicht übertrieben. Aber ich denke, der Mikrocontroller vom TE dürfte vielleicht mehr haben.



  • DirkB schrieb:

    Und für deine for-Schleife kannst du strncat verwenden.

    Wüsste jetzt nicht wo man da strncat verwenden sollte 😕
    Ich würde einfach Byteweise die Zeichen umschaufeln. Die Aufgabe ist so einfach, hier mit CRT Funktionen um sich zu werfen ist mMn. überhaupt nicht nötig.



  • Sone schrieb:

    hustbaer schrieb:

    vermutlich nicht sehr fett mit RAM und CPU Leistung ausgestatteten

    Ich hab nen Robby mit Mikrocontroller. 2000 (!!!) Byte SRAM, 8Mhz CPU... char[5][100] ist da wohl schon vielleicht übertrieben. Aber ich denke, der Mikrocontroller vom TE dürfte vielleicht mehr haben.

    Ganz im Ernst, 2KB sind für nen uC nicht besonders wenig. Die Dinger gehen ganz weit runter. Ein ATtiny4 hat 32 Byte -- nicht Kilobyte! Aber der hat auch nur 512 Byte Flash, von daher kann man da eh nichts großes machen.

    Die größeren ATmegas gehen dann hoch bis 8KB, und die xmegas (glaub ich) bis 16, aber das ist dann schon echter Luxus (sprich: da muss man schon nen Zehner pro Stück hinlegen). Und auch da wirft man nicht eben mal ein halbes Kilobyte aus reiner Faulheit weg.



  • seldon schrieb:

    Ein ATtiny4 hat 32 Byte -- nicht Kilobyte!

    😮 😮 😮 😮 😮
    Wie groß ist dann erst der L1-Cache?



  • Danke für das rege Feedback! 👍

    Beim uC handelt es sich um einen ATMEGA328, welcher mit 16MHz läuft und über 32KByte Progmem verfügt.
    Unter Verwendung von strtok sind etwas über 11KByte davon belegt, es wird aber vor Fertigstellung de Codes noch etwas dazukommen.

    Nach meinem Posting gestern habe ich noch an einer Lösung, wie von hustbaer vorgeschlagen, gebastelt.
    Performancemäßig läuft die Variante mit strtok aber recht zügig...



  • Sone schrieb:

    Wie groß ist dann erst der L1-Cache?

    Witzbold.

    Bananenbieger schrieb:

    Beim uC handelt es sich um einen ATMEGA328, welcher mit 16MHz läuft und über 32KByte Progmem verfügt.

    RAM hat der auch nur 2K. Allerdings kann man sich bei 32K Progmem wohl erlauben, ein paar Bibliotheksfunktionen da reinzulegen (abhängig davon, was du mit dem Ding eigentlich vorhast), und die strtok-Implementation in der avr-libc (ich geh mal davon aus, dass du avr-gcc benutzt) ist auch nicht besonders groß. Das sollte schon in Ordnung gehen.



  • strtok wird vermutlich noch gehen. sscanf wäre aber vermutlich etwas krass wenn man insgesamt nur 32K hat.


Log in to reply