Forum: Mikrocontroller und Digitale Elektronik sscanf liest ersten parameter nicht


von Seppel V. (seppelv)


Lesenswert?

Hallo,

mit sscanf(STM32) will ich mehrere Parameter einlesen, das Problem ist 
dass er den ersten offensichtlich nicht einliest und der Parameter ist 
Null, sollte aber 1 sein. Die nachfolgenden werden problemlos 
eingelesen.

Woran kann das liegen?

Vielen Dank, Grüße, Seppel

---------------------------------
Gesendeter String: "PARAM_POS 1 2 33.3"

---------------------------------
Code:
1
uint16_t axis = 0U;
2
uint16_t iter = 0U;
3
float parameter = 0.0;
4
5
#include <string.h>
6
7
if (strncmp((const char *)usbRxBuffer,"PARAM_POS",9)==0U)
8
{
9
  sscanf(&usbRxBuffer[10], "%u %u %f", &axis, &iter, &parameter);
10
  SensorPosSetParam(axis,iter,parameter);
11
}
---------------------------------
Ergebnis, axis wird nicht eingelesen, aber warum?:

usbRxBuffer = PARAM_POS 1 2 33.3\0\0......

axis = 0

iter = 2

param = 33.2999992

von Clemens L. (c_l)


Lesenswert?

%u ist unsigned int.

Für uint16_t brauchst du so etwas:
1
#include <inttypes.h>
2
3
sscanf(&buffer[10], "%"PRIU16" %"PRIU16" %f", &...);

von Seppel V. (seppelv)


Lesenswert?

Clemens L. schrieb:
> %u ist unsigned int.
>
> Für uint16_t brauchst du so etwas:#include <inttypes.h>
> sscanf(&buffer[10], "%"PRIU16" %"PRIU16" %f", &...);

Hallo,

könntest Du bitte den Code vervollständigen und mir erklären warum das 
mit uint16_t wie auch uint32_t nicht funktioniert?

Ich denke dass ich nicht der einzige bin der darüber stolpert, da sind 
vollständige Posts, mit funktionalem Code und Erklärung sinnvoll. Auch 
die innen liegenden Anführungszeichen, was tun die?

Vielen Dank, Grüße Seppel

: Bearbeitet durch User
von J. S. (jojos)


Lesenswert?

der Code funktioniert wenn ich den auf online gdb eingebe:

https://onlinegdb.com/nD89zYOS1D
1
#include <stdio.h>
2
#include <stdint.h>
3
4
const char usbRxBuffer[] = "PARAM_POS 1 2 33.3";
5
6
int main()
7
{
8
    printf("Hello World");
9
    
10
    uint16_t axis = 0U;
11
    uint16_t iter = 0U;
12
    float parameter = 0.0;
13
14
    #include <string.h>
15
16
    if (strncmp((const char *)usbRxBuffer,"PARAM_POS",9)==0U)
17
    {
18
        sscanf(&usbRxBuffer[10], "%u %u %f", &axis, &iter, &parameter);
19
        printf("result: %d %d %f", axis, iter, parameter);
20
    }
21
22
23
    return 0;
24
}

Bei uint16_t zwar mit Warnung, aber Ergebnis ist korrekt.

da würde ich davon ausgehen das der Inhalt von usbRxBuffer doch nicht so 
ist wie gedacht. Was sagt der Debugger? Oder ein printf vom usbRxBuffer?

von Rolf M. (rmagnus)


Lesenswert?

Clemens L. schrieb:
> %u ist unsigned int.
>
> Für uint16_t brauchst du so etwas:
> #include <inttypes.h>
> sscanf(&buffer[10], "%"PRIU16" %"PRIU16" %f", &...);

Nicht PRIU16, sondern SCNu16. PRI -> printf-Familie, SCN -> 
scanf-Familie. Außerdem würde ich da Leerzeichen drumherum machen. In C 
ist das zwar nicht unbedingt nötig, aber in C++ bekommt man ohne eine 
Fehlermeldung.

Seppel V. schrieb:
> könntest Du bitte den Code vervollständigen und mir erklären warum das
> mit uint16_t wie auch uint32_t nicht funktioniert?

Weil die Größe nicht stimmt, zumindset bei uin16_t. %u ist ist für 
unsigned int, der auf einem ARM normalerweise 32 Bit ist. Du übergibst 
sscanf einen Zeiger auf einen 16-Bit-Wert, aber sscanf versucht 
entsprechend deiner Angabe, von dort stattdessen 32 Bit zu lesen, was 
natürlich falsch ist.
Für die typedefs aus stdint.h wie uint16_t gibt es entsprechende Makros, 
die den richtigen Format-Specifier für den jeweiligen Typen 
bereitstellen. Statt also "%u" musst du "%" SCNu16 schreiben, um den 
richtigen Format-Specifier für uint16_t in scanf zu bekommen.

: Bearbeitet durch User
von J. S. (jojos)


Lesenswert?


von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Unabhängig vom obigen Size-Problem der Parameter:

Es empfiehlt sich (fast) immer, den Return-Wert von sscanf() zu prüfen. 
Hier wird die Anzahl der tatsächlich gefüllten Parameter zurückgegeben. 
Diese sollte man als erstes Kriterium für ein erfolgreiches Matching 
heranziehen.

von Seppel V. (seppelv)


Lesenswert?

Hallo,

was funktioniert:
1
#include <stdio.h>
2
#include <stdint.h>
3
4
char charBuffer1[64];
5
uint16_t axis = 0U;
6
uint16_t iter = 0U;
7
8
sscanf(&usbRxBuffer[0], "%s %"PRIu16" %"PRIu16" %f", charBuffer1, &axis, &iter, &parameter);

Vielen Dank, Grüsse, Seppel

von Rolf M. (rmagnus)


Lesenswert?

Ist trotzdem falsch. Es muss immer noch SCNu16 heißen, nicht PRIu16, und 
ja, das macht einen Unterschied.

von J. S. (jojos)


Lesenswert?

nicht portabel, aber auf dem STM32 funktioniert das auch:
1
  uint16_t axis = 0U;
2
  uint16_t iter = 0U;
3
  float parameter = 0.0f;
4
5
  if (strncmp((const char *)usbRxBuffer,"PARAM_POS",9)==0U)
6
  {
7
      sscanf(&usbRxBuffer[10], "%hu %hu %f", &axis, &iter, &parameter);
8
  }

lässt man das h weg, dann schreibt sscanf Variablen auf dem Stack 
kaputt.

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.