Hallo Leute,
ich arbeite an einem kleinen Protokoll zur Datenübertragung und möchte
eingehende Strings in Unterkomponenten zerlegen. Dazu verwende ich den
Befehl strtok_r(). Leider bekomme ich bei der Zerlegung einen mir nicht
erklärbaren fehler.
Zum Protokoll:
Es werden Zeichenketten des Stils <49;5;XYZ;hello> übermittelt.
49 ist irgendeine Prüfsumme
5 ist die Länge des Parameters von XYZ (also hier von hello)
XYZ soll irgendein Befehl sein (hat immer die Länge 3)
Bei meiner Funktion decode() wird nun von "<49;5;XYZ;hello>" das erste
und das letzte Zeichen abgeschnitten, es bleibt also "49;5;XYZ;hello"
über.
Dann wird das ganze mit strtok_r zerlegt.
Hier etwas Code:
char *token;
char *tmp;
uint8_t j=0;
//lösche ersten char
for (int i=0; i<strlen(RS232.Cmd); i++) {
RS232.Cmd[i]=RS232.Cmd[i+1];
}
RS232.Cmd[strlen(RS232.Cmd)-1]='\0'; //lösche letzten char
token=strtok_r((char*)RS232.Cmd,";", &tmp);
Command.crc=atoi(token); //ergibt die crc
while (token != NULL ) {
if (j==0) {
token = strtok_r(NULL,";", &tmp);
uart_puts(token);
//Command.Par_l=atoi(token);
}
else
if (j==1) {
token = strtok_r(NULL,";", &tmp);
for(int i=0; i<3; i++) Command.Cmd[i]=token[i];
}
else
if (j==2) {
token = strtok_r(NULL,";", &tmp);
for(int i=0; i<Command.Par_l; i++) Command.Par[i]=token[i];
}
j++;
}
Das Problem taucht auf, sobald ich (bei j==0) den zweiten Substring
bekommen will, also um genau zu sein, wenn ich die "5" raustrennen will.
Da das nicht funktioniert hat, habe ich mir das token einfach mal
anzeigen lassen. Dabei ist mir aufgefallen, dass da nie eine 5 steht,
sondern ein "5(". Wo kommt dieses '(' her?
Wenn ich als Checksumme jetzt keine zweistellige Zahl übermittle (also
z.B.: "<4;5;XYZ;hello>" dann funktioniert das heraustrennen der 5
einwandfrei.
Mein System: ATMega23, avr-gcc (GCC) 4.1.2 (WinAVR 20070525)
Habt vielen Dank fpr eure Hilfe, ich bin mit meinen Lateien nämlich am
Ende ;(
Viele Grüße,
Simon
Hallo nochmal.
Ich habe festgestellt, dass wenn ich die Zeile
Command.crc=atoi(token);
herauskommentiere das Problem nicht mehr vorliegt. Kann mir jemand
erklären, welchen einfluss atoi auf token nimmt?
Viele Grüße,
Simon
Das sollte funktionieren (zumindest das aufspalten).
Nur ist das in der jetzigen Form eine Endlosschleife (token wird nie
NULL) und beim Befüllen von Command.Cmd bzw. Command.Par wird das
terminierende '\0' (absichtlich?) nicht mitkopiert.
Hallo,
nein eigentlich ist das nicht beabsichtigt,
aber ich verstehe nicht ganz:
- wieso wird token niemals NULL?
- wie kann ich das terminierende \0 mitkopieren?
Viele Grüße,
Simon
Simon O. wrote:
> - wieso wird token niemals NULL?
Sollte eigentlich schon NULL werden
> - wie kann ich das terminierende \0 mitkopieren?
wie wäre es mit dem Einsatz von strcpy() anstatt deiner
selbstgebastelten Schleifen.
Vereinfach mal dein Programm und sieh dir jeden Teilstring an.
Das sieht alles extrem überkompliziert aus.
1
#include<stdio.h>
2
#include<stdlib.h>
3
#include<string.h>
4
5
typedefunsignedcharuint8_t;
6
7
structCmd_t
8
{
9
intcrc;
10
intPar;
11
charCmd[20];
12
charPar_1[20];
13
};
14
15
structRS232_t
16
{
17
charCmd[200];
18
};
19
20
intmain()
21
{
22
structRS232_tRS232;
23
structCmd_tCommand;
24
25
char*first;
26
char*token;
27
char*tmp;
28
uint8_tj=0;
29
30
strcpy(RS232.Cmd,"<49;5;XYZ;hello>");
31
32
33
// den String hinten um ein Zeichen kürzen
34
RS232.Cmd[strlen(RS232.Cmd)-1]='\0';
35
36
// und den Startpointer um 1 Zeichen vorsetzen
37
first=RS232.Cmd+1;
38
39
token=strtok_r(first,";",&tmp);
40
Command.crc=atoi(token);
41
42
token=strtok_r(NULL,";",&tmp);
43
Command.Par=atoi(token);
44
45
token=strtok_r(NULL,";",&tmp);
46
strcpy(Command.Cmd,token);
47
48
token=strtok_r(NULL,";",&tmp);
49
strcpy(Command.Par_1,token);
50
51
printf("Crc %d\n",Command.crc);
52
printf("Par %d\n",Command.Par);
53
printf("Cmd %s\n",Command.Cmd);
54
printf("1: %s\n",Command.Par_1);
55
}
Funktioniert so, wie man es erwartet. Dein Fehler liegt wahrscheinlich
in dem Code den du nicht zeigst. Ich vermute mal das übliche: Irgend-
ein Array Overflow.
Wieso wird token niemals NULL?
Was passiert wenn j == 2 ist?
token zeigt auf "hello" und wird kopiert, j wird 3, danach wird wieder
token != NULL ausgewertet, j wird 4... d.h. z.B. soetwas daraus machen
1
while(token!=NULL){
2
token=strtok_r(NULL,";",&tmp);
3
if(j==0){
4
Command.Par_l=atoi(token);
5
}
6
...
7
}
oder direkt eine for-Schleife draus machen oder die Lösung von oben
nehmen...
Wie kann ich das terminierende \0 mitkopieren?
Ein Zeichen mehr umkopieren.
> Ich vermute mal das übliche: Irgendein Array Overflow.
aber strcpy vorschlagen ;-)
hm okay, wenn das überkompliziert ist wundert's mich nicht, dass ich
hier ewigkeiten über den Protokoll brüte.
Vielen Dank jedenfalls, werde mal den Code vereinfachen. Übrigens: den
Code, den ich nicht gezeigt habe sieht ziemlich genau so aus wie du ihn
hingeschrieben hast.
Viele Grüße Simon
Hallo,
mit der Vereinfachung hat alles wesentlich passender hingehauen. Ich
habe auch noch ein Array vergrößert (Command.Cmd), das hatte nämlich
regelmäßig einen Overflow gehabt deswegen kam häufig sch*** raus ;\
Aber dank euch schlauen Köpfen bin ich jetzt ein Stück weiter.
Viele Grüße,
Simon
P.S.: Bin auch noch AVR-GCC anfänger, ursprünglich komme ich aus der VCL
verwöhnten Welt von Borland ;) Insofern gibt's noch viel zu lernen =)