Forum: Mikrocontroller und Digitale Elektronik AVR: char arry in string copieren + fehlerhaftes Verhalten


von A. F. (artur-f) Benutzerseite


Lesenswert?

Ich habe eine Funktion zum Empfangen von Strings über USART geschrieben. 
Dabei wurde ein String sowie ein Char Array global deklariert. Mein 
Problem ist folgendes. Wenn ich ein String versende "hans wurst", 
empfange ich auch "hans wurst". Dies kann ich unendlich oft machen und 
alles klappt wunderbar. Sobald sich aber die Zeichenkette ändert, z.B: 
von "hans wurst" in "hans peter" taucht nach dem ersten Empfang von 
"hans peter" an der ersten Position des Strings ein nicht darstellbares 
Zeichen "0x03". Danach kann ich "hans peter" so oft wie ich möchte 
fehlerfrei senden. Wie ich festgestellt habe sehen die Daten im Char 
Array noch ok aus. Also beim versenden von verschiedenen Zeichenketten 
immer das richtige Ergebnis ohne "0x03". Nur halt beim Wechseln von 
Zeichenketten. Gebe ich die Char_Array aus, ist die Welt heil. Also wird 
das Problem beim Umkopieren vom Char Array nach String auftauchen, was 
ich mir jedoch nicht erklären kann.

Hier ist mein Code:
1
char *my_str;
2
char char_arr[127];
3
4
u8 uart_getc(void) {
5
6
    while (!(UCSR1A & (1<<RXC1)));   
7
    return UDR1;                    
8
}
9
 
10
void uart_gets(u8 max_size) {
11
12
  u8 new_char;
13
  static u8 len;
14
  new_char = uart_getc();            
15
                                      
16
                                  
17
  if (new_char != ']' && len < max_size) {
18
     char_arr[len]  = new_char;
19
    len++;
20
  } 
21
  else {
22
  my_str     = char_arr;  // ist das falsch? 
23
  my_str[len]   = '\0';
24
25
  // release received string
26
  len       = 0;
27
  received     = 1;
28
  
29
/*
30
  if (my_str[0] == 0x03) {
31
    my_str += 1;
32
  }
33
*/
34
  }
35
36
}
37
38
ISR (USART1_RX_vect) {
39
   uart_gets(MAX_STR_LEN);
40
}

PS: Für my_str reserviere ich via malloc zum Programmstart 200 Bytes.

von Peter (Gast)


Lesenswert?

my_str     = char_arr;  // ist das falsch?

ja, vermutlich. Damit zeigt der pointer my_str bloss auf den String, 
dabei wird überhaupt kein String kopiert und deine reserviere 200byte 
sind für immer weg.

von Cagara (Gast)


Lesenswert?

Versuch mal stattdessen:

memcpy ( my_str, &(char_arr[0]), len )

von A. F. (artur-f) Benutzerseite


Lesenswert?

> Damit zeigt der pointer my_str bloss auf den String
> dabei wird überhaupt kein String kopiert
Das ist eigentlich auch mein Ziel gewesen.

> und deine reserviere 200byte sind für immer weg.
das stimmt

> Versuch mal stattdessen:
> memcpy ( my_str, &(char_arr[0]), len )

Das fürt komischerweise dazu, dass in my_str nichts mehr steht (getestet 
mit printf), was ich mir überhaupt nicht erklären kann.

von Peter (Gast)


Lesenswert?

> > Damit zeigt der pointer my_str bloss auf den String
> > dabei wird überhaupt kein String kopiert
> Das ist eigentlich auch mein Ziel gewesen.
aber warum sollte man soetas machen, dann hast du 2 Variablen die auf 
das gleiche zeigen. Beide sind global.
Warum nicht nur char char_arr[127]; verwenden?

von Daniel C. (cagara)


Angehängte Dateien:

Lesenswert?

Es muss aber gehen, siehe beweisfoto im anhang:
1
int main(int argc, char* argv[])
2
{
3
  char* my_str;
4
  char char_arr[25];
5
  my_str = (char*)malloc(sizeof(char)*25);
6
7
  char_arr[0]='H';
8
  char_arr[1]='a';
9
  char_arr[2]='l';
10
  char_arr[3]='l';
11
  char_arr[4]='o';
12
  char_arr[5]=0x00;
13
  unsigned int len=6;
14
15
  memcpy(my_str,&(char_arr[0]),len*sizeof(char));
16
17
  printf("Ergebnis: %s\n",my_str);
18
  system("pause");
19
20
  return 0;
21
}

von Daniel C. (cagara)


Lesenswert?

Peter wrote:
>> > Damit zeigt der pointer my_str bloss auf den String
>> > dabei wird überhaupt kein String kopiert
>> Das ist eigentlich auch mein Ziel gewesen.
> aber warum sollte man soetas machen, dann hast du 2 Variablen die auf
> das gleiche zeigen. Beide sind global.
> Warum nicht nur char char_arr[127]; verwenden?

Na weil vielleicht schon was neues eingelesen wird, während das alte 
noch gebraucht wird :)

von P. S. (Gast)


Lesenswert?

Du solltest zuerst einmal auf globale Variablen und statische 
Funktionsvariablen verzichten. Beide raechen sich meist frueher oder 
spaeter bitterlich.

Uebergib einfach das Array in das der String eingefuellt werden soll und 
die maximale Laenge. Abfuellen, fertig und die Funktion hat keine 
Seiteneffekte, ist Threadsafe, etc, pp.

In deinem konkreten Fall ist len beim ersten Aufruf nicht bewusst auf 0 
initialisiert. Mit Glueck macht dein Compiler das fuer dich - je nach 
Compiler aber auch nicht :-/

Kritisch an der Implementierung ist auch, dass Buffer max_size + 1 gross 
sein muss, da du im Zweifelsfall die Terminierung auf my_str[len] 
schreibst, wobei len = max_size ist. Hast du das beachtet?

Auch fraglich: Du liest ein Zeichen und pruefst erst dann, ob du noch 
Platz im String hast. Ist der String schon voll, wirfst du das Zeichen 
weg.

von A. F. (artur-f) Benutzerseite


Lesenswert?

> Es muss aber gehen, siehe beweisfoto im anhang:
Ja so die graue Theorie :/
Ich wüsste auch nicht, was dagegen sprechen sollte.


>Du solltest zuerst einmal auf globale Variablen und statische
>Funktionsvariablen verzichten. Beide raechen sich meist frueher oder
>spaeter bitterlich.

Dass char_arr nicht global sein müsste gebe ich dir recht, my_str muss 
aber.

>In deinem konkreten Fall ist len beim ersten Aufruf nicht bewusst auf 0
>initialisiert. Mit Glueck macht dein Compiler das fuer dich - je nach
>Compiler aber auch nicht :-/

Wieso mit Glück? Steht zumindest in der gcc Doku, dass es der Fall ist.

Kritisch an der Implementierung ist auch, dass Buffer max_size + 1 gross
sein muss, da du im Zweifelsfall die Terminierung auf my_str[len]
schreibst, wobei len = max_size ist. Hast du das beachtet?
> my_srt buffer ist auf jeden Fall größer.

>Auch fraglich: Du liest ein Zeichen und pruefst erst dann, ob du noch
>Platz im String hast. Ist der String schon voll, wirfst du das Zeichen
>weg.

Oh ja, ist zwar nicht tötlich in meinem Fall, danke trotzdem. Werde 
aufbessern.


Also, ich bin bis jetzt nicht wirklich zu einem Entschluss gekommen, 
woran es liegt :(. Die STRINGS in AVR sind echt eine Sache für sich.

von Peter (Gast)


Lesenswert?

> >In deinem konkreten Fall ist len beim ersten Aufruf nicht bewusst auf 0
> >initialisiert. Mit Glueck macht dein Compiler das fuer dich - je nach
> >Compiler aber auch nicht :-/

> Wieso mit Glück? Steht zumindest in der gcc Doku, dass es der Fall ist.
Sicher? bei den MS7 Compiler weiss ich das es nur in der Debug version 
der fall ist, in der Release kann da alles drin stehen. Im ansi wird es 
nicht definiert sein und ich würde mich bestimmt nicht darauf verlassen.

von Daniel C. (cagara)


Lesenswert?

Uninitialisierte Variablen haben nachdem sie deklariert wurden einen 
beliebigen Wert. Deswegen solltest du an der stelle auch ne 
compilerwarnung bekommen.

von P. S. (Gast)


Lesenswert?

∀ℜτ∪ℜ ΦΥΗΚ wrote:

>>Du solltest zuerst einmal auf globale Variablen und statische
>>Funktionsvariablen verzichten. Beide raechen sich meist frueher oder
>>spaeter bitterlich.
> Dass char_arr nicht global sein müsste gebe ich dir recht, my_str muss
> aber.

Nein, muss es nicht. Und ganz sicher musst du nicht aus einer 
Hilfsfunktion darauf zugreifen.

>>In deinem konkreten Fall ist len beim ersten Aufruf nicht bewusst auf 0
>>initialisiert. Mit Glueck macht dein Compiler das fuer dich - je nach
>>Compiler aber auch nicht :-/
> Wieso mit Glück? Steht zumindest in der gcc Doku, dass es der Fall ist.

Es gibt noch mehr Compiler als den gcc. Bricht es dir einen Zacken aus 
der Krone, die Initialisierung zu machen?

> Kritisch an der Implementierung ist auch, dass Buffer max_size + 1 gross
> sein muss, da du im Zweifelsfall die Terminierung auf my_str[len]
> schreibst, wobei len = max_size ist. Hast du das beachtet?
>> my_srt buffer ist auf jeden Fall größer.

Ah ja.

> Also, ich bin bis jetzt nicht wirklich zu einem Entschluss gekommen,
> woran es liegt :(. Die STRINGS in AVR sind echt eine Sache für sich.

Nein, die sind ganz einfach. Du hast genuegend Tips bekommen, wo es 
ueberall hakt - nun schreibe mal eine saubere Funktion, die auch einfach 
testbar ist, dann geht das schon.

von Roland R. (roland) Benutzerseite


Lesenswert?

Ungetestet:
1
#define BUFFER_SIZE 128
2
3
static char buffer1[BUFFER_SIZE] = { 0 };
4
static char buffer2[BUFFER_SIZE] = { 0 };
5
static char* buffer_receiving = buffer1;
6
static char* buffer_finished = buffer2;
7
static unsigned char buffer_pos = 0;
8
9
void uart_gets()
10
{
11
  char c = uart_getc();
12
13
  if(c != ']' && buffer_pos < BUFFER_SIZE - 1)
14
  {
15
    buffer_receiving[buffer_pos++] = c;
16
  }
17
  if(c == ']' || buffer_pos >= BUFFER_SIZE - 1)
18
  {
19
    char* swap = buffer_finished;
20
21
    buffer_receiving[buffer_pos] = '\0';
22
23
    buffer_finished = buffer_receiving;
24
    buffer_receiving = swap;
25
    buffer_pos = 0;
26
27
    /* do something with buffer_finished here */
28
  }
29
}

Wobei noch darauf geachtet werden muss, dass nicht während der 
Verarbeitung von buffer_finished der enthaltene Zeiger durch den Empfang 
des nächsten Textes umgebogen wird.

Gruß,
Roland

von yalu (Gast)


Lesenswert?

> In deinem konkreten Fall ist len beim ersten Aufruf nicht bewusst auf
> 0 initialisiert. Mit Glueck macht dein Compiler das fuer dich - je
> nach Compiler aber auch nicht :-/

> Wieso mit Glück? Steht zumindest in der gcc Doku, dass es der Fall
> ist.

> Sicher? bei den MS7 Compiler weiss ich das es nur in der Debug version
> der fall ist, in der Release kann da alles drin stehen.

> Uninitialisierte Variablen haben nachdem sie deklariert wurden einen
> beliebigen Wert. Deswegen solltest du an der stelle auch ne
> compilerwarnung bekommen.

Ja was denn nun? Fragen wir doch den Gesetzgeber, und der sagt:

  "If an object that has automatic storage duration is not initialized
  explicitly, its value is indeterminate. If an object that has static
  storage duration is not initialized explicitly, then:

  — if it has pointer type, it is initialized to a null pointer;

  — if it has arithmetic type, it is initialized to (positive or
    unsigned) zero;

  — if it is an aggregate, every member is initialized (recursively)
    according to these rules;

  — if it is a union, the first named member is initialized
    (recursively) according to these rules."

len hat dank des /static/-Schlüsselworts "static storage duration" und
wird deswegen implizit mit 0 initialisiert.

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.