Forum: Mikrocontroller und Digitale Elektronik Zu blöd für sscanf?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von H.Joachim S. (crazyhorse)


Bewertung
0 lesenswert
nicht lesenswert
Ich glaube, ich habe einen Knoten im Hirn.
Parser für serielle Daten

uint16_t adr, channel, value;
printf ("%s\r\n", &frame_buffer[5]);
if (sscanf (&frame_buffer[5],"%u,%u,%u",&adr,&channel,&value)==3)
   {printf ("%u,%u,%u", adr, channel, value);
    if (adr==modul_adr)
       {
       }
   }
die printf sind nur Testausgaben
Nr.1 liefert
12,1,60000<\r><\n>
das ist korrekt und entspricht den gesendeten Daten
Nr2:
0,1,60000
adr ist immer 0, egal was da gesendet wird, dementsprechend passt der 
Adressvergleich natürlich nicht.

Ja, ich weiss, das Problem sitzt fast immer vor der Tastatur....

von Markus M. (adrock)


Bewertung
0 lesenswert
nicht lesenswert
Evtl. sind vor dem eigentlichen String noch irgendwelche unsichtbaren 
Steuerzeichen (z.B. "\r") im &frame_buffer[5] vorhanden, die zwar beim 
printf("%s...") egal sind, dem sscanf() aber nicht schmecken?

von H.Joachim S. (crazyhorse)


Bewertung
0 lesenswert
nicht lesenswert
Ne, nichts.
Das bekomme ich geliefert:
{"WR",12,1,60000}
habs mir auch mit Hterm angeschaut, da ist nichts weiter drin, auch 
keine Leerzeichen.
Die gesamte Botschaft in geschweiften Klammern, '{' als Startzeichen und 
wird entfernt, '}' durch 0 ersetzt in der Empfangsroutine.
Und in frame_buffer (ja, ist gross genug) steht dann wirklich
"WR",12,1,60000\0

if (!strncmpf (frame_buffer, "\"WR\",",5 )
   {//hier komme ich an
   }

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Die 5 für deine frame_buffer array Größe kommt mir falsch vor.

Es geht doch darum, den Inhalt von frame_buffer auf die Variablen 
aufzuteilen, oder sehe ich das falsch?

Habe das mal mit gcc in Linux gemacht:
1
#include "stdio.h"
2
3
int main()
4
{
5
  unsigned int adr, channel, value;
6
  char s1;
7
  int res;
8
9
  char frame_buffer1[]="12,1,60000<\r><\n>";
10
  res=sscanf(frame_buffer1,"%u,%u,%u",&adr,&channel,&value);
11
  printf ("\n%u,%u,%u\n", adr, channel, value);
12
  printf ("Ergebnis sscanf: %d\n\n",res);
13
14
  char frame_buffer2[20]={"W,0,1,60000,0x70"};
15
  res=sscanf(frame_buffer2,"%c,%u,%u,%u",&s1,&adr,&channel,&value);
16
  printf ("%c,%u,%u,%u\n", s1, adr, channel, value);
17
  printf ("Ergebnis sscanf: %d\n\n",res);
18
19
  char frame_buffer3[]="99,1,60000<\r><\n>";
20
  res=sscanf(frame_buffer3,"%u,%u,%u",&adr,&channel,&value);
21
  printf ("\n%u,%u,%u\n", adr, channel, value);
22
  printf ("Ergebnis sscanf: %d\n\n\n",res);
23
}

Es gibt dabei verschiedene Größen und Definitionen von frame_buffer.

Sollte das nicht so ablaufen?

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hier noch die Ausgaben dazu:

12,1,60000
Ergebnis sscanf: 3

W,0,1,60000
Ergebnis sscanf: 4


99,1,60000
Ergebnis sscanf: 3

von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
%u erwartet unsigned int, das ist aber nicht auf jedem System ein 
uint16_t. Versuchs's mal mit unsigned int statt uint16_t.

von zitter_ned_aso (Gast)


Bewertung
0 lesenswert
nicht lesenswert
pegel schrieb:
> Die 5 für deine frame_buffer array Größe kommt mir falsch vor.

Da ist keine Arraygröße - er startet dort an zu lesen.

Auch bei mir auf dem Rechner funktioniert alles wie gewünscht:
1
#include <stdio.h>
2
#include <stdint.h>
3
4
int main ()
5
{
6
7
char frame_buffer[]="\"WR\",12,1,60000, 42 und viel mehr";
8
9
uint16_t adr, channel, value;
10
11
printf ("ausgabe 1: %s\r\n", &frame_buffer[5]);
12
13
14
if (sscanf (&frame_buffer[5],"%hu, %hu, %hu" ,&adr,&channel,&value)==3)
15
   {
16
       printf ("ausgabe 2: %u, %u, %u", adr, channel, value);
17
18
   }
19
20
    return 0;
21
}


nur bei sscanf gab es Warnungen weil uint16_t auf meinem PC unsigned 
shorts sind. Also muss man da %hu nehmen (statt %u). Siehe oben.

von H.Joachim S. (crazyhorse)


Bewertung
0 lesenswert
nicht lesenswert
Danke für die Mühe, ich werde es auch gleich mal mit nem anderen 
Compiler probieren, muss mal schauen was ich habe

was liefert:
char frame_buffer1[]="xx12,1,60000<\r><\n>";
res=sscanf(&frame_buffer1[2],"%u,%u,%u",&adr,&channel,&value);
bei dir?

von pegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
12,1,60000
Ergebnis sscanf: 3

von zitter_ned_aso (Gast)


Bewertung
0 lesenswert
nicht lesenswert
H.Joachim S. schrieb:
> char frame_buffer1[]="xx12,1,60000<\r><\n>";

Die drei Zahlen werden extrahiert. Egal welchen String man nimmt.

von H.Joachim S. (crazyhorse)


Bewertung
0 lesenswert
nicht lesenswert
Also wohl doch der berühmte Compilerfehler?
CodeVision 3.33

von foobar (Gast)


Bewertung
1 lesenswert
nicht lesenswert
> uint16_t adr, channel, value;
> sscanf (&frame_buffer[5],"%u,%u,%u",&adr,&channel,&value)

> Also wohl doch der berühmte Compilerfehler?

Nix Compilerfehler - haben doch schon genug Leute geschrieben: %u für 
unsigned int, %hu für unsigned short.  Deine Variante läuft nur auf 
Systemen mit 16-bit-ints richtig, auf allen anderen zermantscht sie den 
Speicher.

Wenn du unbedingt uint16_t benutzen willst, musst du inttypes.h includen 
und dann SCNu16 als Specifier benutzen:

sscanf(str, "%"SCNu16",%"SCNu16",%"SCNu16, &adr,&channel,&value);

Nicht schön, aber die einzig portable Variante.

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht lesenswert
foobar schrieb:
> Nicht schön, aber die einzig portable Variante.

Wenn die Leute meinen, dass sie unbedingt die Typen aus stdint.h nehmen 
müssen, dann sollen sie auch leiden :-)

Denn meist sind die einfachen Typen wie uint16_t die falsche Wahl.

uint_least16_t oder uint_fast16_t sind oft besser geeignet.

von H.Joachim S. (crazyhorse)


Bewertung
0 lesenswert
nicht lesenswert
Muss nicht portabel sein. Läuft auf einem AVR (Mega168) und bleibt auch 
dort. Bei Gelegenheit werde ich da noch mal dran gehen, habs jetzt erst 
mal "zu Fuss" auseinander klamüsert.
Mit unsigned int und unsigned char dasselbe Verhalten

der erste Teil war:
if (!strncmpf (frame_buffer, "\"RD\",",5 ))
    {if (sscanf (&frame_buffer[5], "%u", &adr)==1)
        {if (adr==modul_adr)
             {
             }
        }
     }

und funktioniert, mit nur einen Parameter.
Bei mehr als einem ist immer der erste 0, alle folgenden sind korrekt

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht lesenswert
%u ist für unsigned int
%hu ist für unsigned short
%hhu ist für unsigned char (seit C99)

Bei %u beschreibt scanf sizeof(int) Bytes
Wenn die Variable aber weniger Bytes belegt, wird über deren Grenze 
hinaus geschrieben und andere Variablen überschrieben.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.