www.mikrocontroller.net

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


Autor: A. F. (artur-f) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
char *my_str;
char char_arr[127];

u8 uart_getc(void) {

    while (!(UCSR1A & (1<<RXC1)));   
    return UDR1;                    
}
 
void uart_gets(u8 max_size) {

  u8 new_char;
  static u8 len;
  new_char = uart_getc();            
                                      
                                  
  if (new_char != ']' && len < max_size) {
     char_arr[len]  = new_char;
    len++;
  } 
  else {
  my_str     = char_arr;  // ist das falsch? 
  my_str[len]   = '\0';

  // release received string
  len       = 0;
  received     = 1;
  
/*
  if (my_str[0] == 0x03) {
    my_str += 1;
  }
*/
  }

}

ISR (USART1_RX_vect) {
   uart_gets(MAX_STR_LEN);
}

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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Cagara (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Versuch mal stattdessen:

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

Autor: A. F. (artur-f) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Daniel Cagara (cagara)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Es muss aber gehen, siehe beweisfoto im anhang:
int main(int argc, char* argv[])
{
  char* my_str;
  char char_arr[25];
  my_str = (char*)malloc(sizeof(char)*25);

  char_arr[0]='H';
  char_arr[1]='a';
  char_arr[2]='l';
  char_arr[3]='l';
  char_arr[4]='o';
  char_arr[5]=0x00;
  unsigned int len=6;

  memcpy(my_str,&(char_arr[0]),len*sizeof(char));

  printf("Ergebnis: %s\n",my_str);
  system("pause");

  return 0;
}

Autor: Daniel Cagara (cagara)
Datum:

Bewertung
0 lesenswert
nicht 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 :)

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. F. (artur-f) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Daniel Cagara (cagara)
Datum:

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

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Roland Riegel (roland) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ungetestet:
#define BUFFER_SIZE 128

static char buffer1[BUFFER_SIZE] = { 0 };
static char buffer2[BUFFER_SIZE] = { 0 };
static char* buffer_receiving = buffer1;
static char* buffer_finished = buffer2;
static unsigned char buffer_pos = 0;

void uart_gets()
{
  char c = uart_getc();

  if(c != ']' && buffer_pos < BUFFER_SIZE - 1)
  {
    buffer_receiving[buffer_pos++] = c;
  }
  if(c == ']' || buffer_pos >= BUFFER_SIZE - 1)
  {
    char* swap = buffer_finished;

    buffer_receiving[buffer_pos] = '\0';

    buffer_finished = buffer_receiving;
    buffer_receiving = swap;
    buffer_pos = 0;

    /* do something with buffer_finished here */
  }
}

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

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.