Befehl strcmp wie bei ANSI C?

Gast #2821149
Lesenswert?

Hi ich hab mal eine Frage und zwar wie sich die Funktion strcmp verhält. 
Denn in meinem Beispiel kommt immer true heraus:
1
if(strcmp(uart_answer, "OK\r\n"))
2
  {
3
    led_ok();
4
  }

egal wie die variable uart_answer ist die funktion led_ok() wird immer 
aufgerufen.

Was mache ich verkehrt?
#2821166
Lesenswert?

ben schrieb:
> Wo finde ich denn eine vernünftige Funktions Referenze über die AVR
> Funktionsbibliotheken?


Die sollte eigentlich in deinem C-Lehrbuch zu finden sein, wenn du schon 
das (sicherlich nicht kleine) Kapitel über 'Stringverarbeitung in C' 
nicht gelesen hast. Solltest du lesen! Denn gerade über 
Stringverarbeitung gibt es in C eine Menge zu erzählen und zu beachten.

Ansonsten: Tante Google findet normalerweise mit dem Funktionsnamen auch 
sofort eine Referenzsseite.
"C strcmp"
sollte eigentlich weiter helfen

Als Minimalkurzversion des Allernotwendigsten kann man auch da mal 
reinschauen
String-Verarbeitung in C
#2821189
Lesenswert?

Kan asta schrieb:

> Hahahahahahaha...Hauptsache drauflosklimpern...bei Problemen hilft das
> Spasti-Forum hier.

So läufts doch. Ne Schleife tut nicht was sie soll? Erstmal nen Thread 
starten und 1000 Zeilen Code dumpen. Wozu selbst denken und überlegen? 
Mal ne Debug-Ausgabe reinmachen? Mal den LA raukramen? Nööö.
Ich meine hier scheitert es ja bereits am Nachschauen des Syntax für 
eine Funktion. Klar, das Forum wirds wissen.

Also dann tu ich mal was von mir erwartet wird:

Lieber TE, die strcmp gibt 0 zurück wenn die Strings gleich sind.

gruß cyblord
Gast #2821192
Lesenswert?

hab eine consolen anwendung in c geschrieben und meinen fehler denke ich 
mal gefunden.
1
int main(void)
2
{
3
    char a[20] = "OK\r\n";
4
    char b[20] = "OK\r\n";
5

6
    if(!strcmp(a,b))
7
    {
8
        printf("true");
9
    }else{
10
        printf("false");
11
    }
12

13
    return 0;
14
}

so funktionierts in dem Consolen Projekt aber wenn ich das auf den 
Mikrocontroller portiere und über die UART Schnittstelle ein "OK\r\n" 
bekomme und vergleiche sagt er mir das sie nicht gleich sind aber ich 
habe mir beide ausgeben lassen über mein terminal programm und sie sind 
100% identlisch. Was kann ich noch probieren?
#2821197
Lesenswert?

ben schrieb:
> Was kann ich noch probieren?

Systematisch den Fehler suchen. Also woher weißt du dass deine Funktion 
meint die String wären nicht unterschiedlich? Eventuell liegts an deiner 
led_ok Funktion. Immerhin hast du in diesem Beispiel korrekt die strcmp 
negiert. Hast du das letztendlich in deinem AVR Program auch gemacht? Im 
Eingangspost war es noch nicht so.

gruß cyblord
Gast #2821204
Lesenswert?

Hab mir das alles direkt als Hex ausgeben lassen und gebe es auch nach 
einander als Hex ein. Da sollte kein Fehler sein.

Hier die komplette Vergleichsfunktion:
1
void uart_cmp_answer(void)
2
{
3
  uart_c('\n');
4
  uart_str(uart_answer);
5
  uart_c('\n');
6
  if(strcmp(uart_answer, "OK\r\n") == 0)
7
  {
8
    uart_str("alles ok!!!\n");
9
  }else{
10
    uart_str("fehler!!!\n");
11
  }
12
}

Der einzige Unterschied der mir noch einfällt ist das die variable 
uart_answer kein \0 hat. Wird dieses Zeichen mit vergleichen oder wie 
bei einer Ausgabe Funktion ignoriert?
#2821205
Lesenswert?

ben schrieb:

> habe mir beide ausgeben lassen über mein terminal programm und sie sind
> 100% identlisch.

Wie hast du sie dir ausgeben lassen?

Die sind garantiert nicht identisch, sonst hätte strcmp das bemerkt.
Führende Leerzeichen? Ist die \r\n tatsächlich genau so in beiden 
Strings enthalten? Gibt es da ev. noch nachlaufende Leerzeichen?

Bei der Ausgabe (es sei denn natürlich man sieht sich das alles auf 
Byte-Hex Ebene an) muss man ein wenig vorsichtig sein und auch ins 
Kalkül ziehen, dass es in den Strings Zeichen gibt, die man auf dem 
Terminal bei einer reinen Textausgabe nicht sieht. Wie zb Leerzeichen, 
Tabulator oder auch Zeilenumbruch. Da heist es dann: Wie kann ich meine 
Ausgabe so gestalten, dass ich auch auf solche Dinge mal einen Blick 
werfen kann und mir die Ausgabe darüber etwas erzählt.
#2821211
Lesenswert?

ben schrieb:

> Der einzige Unterschied der mir noch einfällt ist das die variable
> uart_answer kein \0 hat.

Den muss sie haben, sonst ist es in erster Instanz gar kein String. Ein 
String endet dort, wo das \0 ist.

> Wird dieses Zeichen mit vergleichen oder wie
> bei einer Ausgabe Funktion ignoriert?

Da alle Strings IMMER mit einem \0 enden, macht es wenig Sinn, das extra 
zu vergleichen. Durch die Art und Weise wie Strings verglichen werden, 
fällt das automatisch an. Der Vergleich basiert darauf, das im Grunde 
das erste Byte gesucht wird, welches sich in beiden Strings 
unterscheidet. Gelingt dies, ehe \0 erreicht wird, dann sind die Strings 
unterschiedlich.
Gast #2821236
Lesenswert?

Scheinbar stimmt die Länge der beiden Strings schon nicht über ein. Ich 
bin nur von dem ausgegangen, was mir das Terminalprogramm angezeigt hat 
und was ich eingegeben habe.

Ich werde es weiter probieren. Danke trotzdem.
#2821239
Lesenswert?

ben schrieb:
> Scheinbar stimmt die Länge der beiden Strings schon nicht über ein. Ich
> bin nur von dem ausgegangen, was mir das Terminalprogramm angezeigt hat
> und was ich eingegeben habe.

Das stinkt nach dem leidigen \r\n Problem.

Hinweis:
Es ist absolut vernünftig, wenn die Einelesefunktion für Zeilen die 
unausweichlichen \r oder \n gleich entfernt und nicht im String anlegt. 
D.h. in deinem Programm brauchst du dich dann damit nicht mehr 
rumschlagen. Von der Zeileneinlesefunktion kriegst du den String "OK" 
und nur diesen String. Egal, ob jetzt das Terminal (oder allgemeiner: 
die UART Gegenstellen) eine Zeile mit \n, mit \r oder mit \r\n 
abschliesst. Wenn du die unterschiedlichen Varianten immer und überall 
quer durch das ganze Programm berücksichtigen musst, dann wirds 
aufwändig. Aber im Grunde braucht diese Zeichen ja kein Mensch. Du weißt 
ja, dass es sich bei dem String um eine komplette Zeile von der Eingabe 
handelt.
Gast #2821260
Lesenswert?

Nein an der \0 lag es nicht.

jetzt will ich alle \r und \n aus dem string raushalten doch das gelingt 
mir nicht.. mit:
1
unsigned char incomming = UDR;
2

3
...
4

5
if(incomming != 13 || incomming != 10)
6
      {
7
        uart_answer[uart_answer_count] = incomming;
8
        uart_answer_count++;  
9
      }

wenn ich den String immernoch ausgeben lasse, hat er ein \r also 13 oder 
0x0D wie man es auch immer nennen will.

Hab ich da etwas in meiner if-Anweisung falsch?
Moderator Persönliche Seite #2821272
Lesenswert?

ben schrieb:
> Nein an der \0 lag es nicht.

Doch. Du vergisst, den String zu terminieren!

Das folgende ist zwar schon mal besser, weil Du '\n' und '\r' nicht mit 
Dir rumschleppen musst, aber beseitigt nicht Dein Problem.

> if(incomming != 13 || incomming != 10)

Hier muss ein && statt ein || hin.


>       {
>         uart_answer[uart_answer_count] = incomming;
>         uart_answer_count++;
>       }

Schon besser, aber da fehlt immer noch ein

        uart_answer[uart_answer_count] = '\0';

am Ende (Deiner Einleseschleife). Zeig doch mal den kompletten Code 
statt diese Fitzelchen!

Übrigends: verständlicher wäre

  if(incomming != '\r' && incomming != '\n')

statt

  if(incomming != 13 && incomming != 10)
#2821277
Lesenswert?

1
   if(incomming != 13 || incomming != 10)

Den Fehler macht wohl jeder mal.

Gedankenhilfe:
Für jede Zahl, egal was sie ist, gilt
       sie ist entweder NICHT 13
  oder sie ist NICHT 10

selbst dann nicht wenn die Zahl 13 ist. Denn 13 ist ja nicht gleich 10.
d.h. egal was deine Zahl ist, diese Bedingung ist in ihrer Gesamtheit 
für jede Zahl IMMER erfüllt.


(Das dahinerliegende Problem: Wir benutzen im Alltag die Wörter 'nicht' 
'und' 'oder' in einer laxen Form, die sehr darauf basiert, dass unser 
Gegenüber weiß was wir meinen. Oft genug benutzen wir diese Wörter ganz 
einfach falsch und wenn man es genau nimmt, dann bauen wir im Alltag 
völlig falsche 'logische Operationen'. D.h. an dieser Stelle vorsichtig 
sein. Da kann eine 'wortwörtliche' Übersetzung in eine 
Programmiersprache ganz schnell in die Hose gehen. Immer mit ein paar 
Testbeispielen im Kopf durchspielen)
Gast #2821292
Lesenswert?

Kan asta schrieb:
> uart_answer[uart_answer_count++] = incoming;
> uart_answer[uart_answer_count] = 0x00;

VIEL zu langsam, weil ja immer die 0 geschrieben wird.

if(incomming != 13 && incomming != 10) {
   uart_answer[uart_answer_count++] = incoming;
} else {
   uart_answer[uart_answer_count] = 0x00;
}
#2821295
Lesenswert?

Frank M. schrieb:
> Karl Heinz Buchegger schrieb:
>> Das ist doch reine Spekulation bei dem Fitzelchen, den er gezeigt hat.
>
> Klar ist das reine Spekulation, aber es ist die einzige Erklärung, warum
> seine ursprüngliche strcmp-Variante (mit Vergleich auf 0, aber mit
> "\r\n") nicht funktionierte. ;-)
>
> Ich wette daher mal ein Bierchen ;-)

ok. dann wette ich mal ein virtuelles Bierchen auf \r\n Probleme :-)
#2821306
Lesenswert?

Kan asta schrieb:
> Ein Programmierer würde schreiben:
>
> uart_answer[uart_answer_count++] = incoming;
> uart_answer[uart_answer_count] = 0x00;

Ein Programmierer würde vorher abprüfen, ob noch Platz ist für das 
Zeichen && dem '\0'. Und ich vermute uart_answer[] besteht aus Chars, 
dann würde ich zumindest auch ein char zuweisen ('\0') und nicht direkt 
einen Ordinalwert. Macht vllt. keinen Unterschied, aber weist indirekt 
auf die Verwendung von Char hin.
Moderator Persönliche Seite #2821307
Lesenswert?

Peter II schrieb:
> VIEL zu langsam, weil ja immer die 0 geschrieben wird.

Jepp.

> if(incomming != 13 && incomming != 10) {
>    uart_answer[uart_answer_count++] = incoming;
> } else {
>    uart_answer[uart_answer_count] = 0x00;
> }

Hm, auch dieses Fitzelchen überzeugt nicht richtig, weil hier die 
Leseschleife mitsamt der Abbruchbedingung fehlt.

Besser:
1
  while (uart_answer_count < BUFFER_LEN &&
2
        (incoming = uart_getc ()) != '\r' && incoming != '\n')
3
  {
4
     uart_answer[uart_answer_count++] = incoming;
5
  }
6
  uart_answer[uart_answer_count] = '\0';

Damit ist die Terminierung raus aus der Schleife.
#2821310
Lesenswert?

Karl Heinz Buchegger schrieb:
> Peter II schrieb:
>> Kan asta schrieb:
>>> uart_answer[uart_answer_count++] = incoming;
>>> uart_answer[uart_answer_count] = 0x00;
>>
>> VIEL zu langsam, weil ja immer die 0 geschrieben wird.
>
> Völlig wurscht, solange die Zeichen von der UART kommen.

In erster Linie muss es richtig sein. Und dazu gehört auch, dass ein
\r\n nicht als 2 Eingabezeilen gemeldet werden.
Gast #2821313
Lesenswert?

Frank M. schrieb:
> while ((incoming = uart_getc ()) != '\r' && incoming != '\n')
>   {
>      uart_answer[uart_answer_count++] = incoming;
>   }
>   uart_answer[uart_answer_count] = '\0';

nagut, dann noch die länge prüfen
1
while ((incoming = uart_getc ()) != '\r' && incoming != '\n' && uart_answer_count < MAX_INPUT_LEN )
2
  {
3
     uart_answer[uart_answer_count++] = incoming;
4
  }
5
  uart_answer[uart_answer_count] = '\0';
Moderator Persönliche Seite #2821325
Lesenswert?

Peter II schrieb:
> nagut, dann noch die länge prüfen

Meine (und Deine) Lösung haben ein Problem: Ein '\r' bricht die Schleife 
ab und das '\n' bleibt im Input-Buffer und wird erst das nächste mal 
eingelesen. Das führt dann beim Lesen der nächsten Antwort zu einer 
"Leerzeile". Okay, die könnte man einfach ignorieren, aber korrekt wäre 
es so:
1
  while (uart_answer_count < BUFFER_LEN &&
2
        (incoming = uart_getc ()) != '\n')    // Bei NL abbrechen
3
  {
4
     if (incoming != '\r')   // CR ignorieren
5
     {
6
         uart_answer[uart_answer_count++] = incoming;
7
     }
8
  }
9
  uart_answer[uart_answer_count] = '\0';

Da kann man mal sehen, was da alles für Komplikationen eintreten können 
;-)
Gast #2821327
Lesenswert?

Danke und Sorry für den dummen Logikfehler.. und das schlimem ist ich 
murmel mir auch die ganze Zeit ein UND vor...

Ich habe den String terminiert. Das war aber im Quellcode weiter unten 
und zu einer anderen Bedingung.
(Firma: Basta) #2821346
Lesenswert?

Modem? Stand nirgends. Ich vermute, der TO will mit verschiedenen 
Strings verschiedene Leds an- und abschalten. Das würde zu seinen 
Programmierkenntnissen passen.

State Machine? Seh ich nirgens.

256 Funktionen? Du darfst den Array auch mit Null-Zeigern auffüllen.
So kann der TO dann sogar noch per UART resetten.

Frank, sei mir nicht böse aber überlass das Denken besser den anderen.
Moderator Persönliche Seite #2821363
Lesenswert?

Kan asta schrieb:
> Modem? Stand nirgends. Ich vermute, der TO will mit verschiedenen
> Strings verschiedene Leds an- und abschalten.

Dann erklär mal, warum er auf seinem µC die Antwort "OK\r\n" auswerten 
will und nicht "Lampe1 an" oder "Lampe5 aus". Der String "OK\r\n" deutet 
auf die Antwort eines Hayes-kompatiblen Modems (wahrscheinlich ein 
Bluetooth-Adapter) hin.

> Das würde zu seinen Programmierkenntnissen passen.

Das ist reine Spekulation Deinerseits.

> State Machine? Seh ich nirgens.

Ein AT-kompatibles Modem gibt Strings wie "OK\r\n" bzw. "CONNECT\r\n" 
und keine Einzelzeichen aus. Um solche Strings per Einzelzeichen-Analyse 
auszuwerten - wie Du es vorschlägst - braucht man eine Statemachine.

> 256 Funktionen? Du darfst den Array auch mit Null-Zeigern auffüllen.
> So kann der TO dann sogar noch per UART resetten.

Witzbold. Der aktive Part ist hier der µC und nicht das Gegenüber, das 
geht klar aus dem String "OK\r\n" hervor. Der µC sendet einen Befehl und 
das Gegenüber antwortet mit "OK\r\n".

Oder hast Du schon mal einen Befehl namens "OK" gesehen?

> Frank, sei mir nicht böse aber überlass das Denken besser den anderen.

Gerne anderen, aber nicht Dir.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren