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


von H.Joachim S. (crazyhorse)


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)


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)


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)


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)


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)


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)


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)


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)


Lesenswert?

12,1,60000
Ergebnis sscanf: 3

von zitter_ned_aso (Gast)


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)


Lesenswert?

Also wohl doch der berühmte Compilerfehler?
CodeVision 3.33

von foobar (Gast)


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)


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)


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)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.