Forum: Compiler & IDEs Funktionsaufruf (ähnlich strtol) mit Pointer Übergabe


von Tarek T. (tarek_t)


Lesenswert?

Hallo,

ich habe ein Problem, bei dem ich nicht weiterkomme. Ich habe die Suche 
schon benutzt, genauso wie Google. Aber ich denke es ist zu speziell.

Es geht um folgendes:

Ein ATmega32 soll Schrittmotoren für eine CNC-Fräse steuern. Die 
Steuerungsbefehle in Form von G-Code bekommt der Controller von einem 
angeschlossenen Computer.

Jetzt möchte ich mein Programm für den Controller etwas umbauen um mehr 
Performance rauszuholen. Im Programm des Controllers kommt dieser 
irgendwann an die Stelle, an der er den G-Code verarbeitet.

Für folgende Beispiele wird folgender G-Code angenommen:

G01 X12.125 Y20.7123

Bisher sah es so aus:
1
int value = (int)strtol(valStart, &valEnd, 10);

wobei valStart ein Pointer ist, der auf den ersten Char nach zugehörigem 
Befehl zeigt. Zu Beginn also auf '0' (gehört zu "G01"). Die Funktion 
wertet die Zeichenkette bis zum Vorkommen des ersten ungültigen Zeichens 
aus. In dem Beispiel das Leerzeichen vor X. Die Variable "value" enthält 
danach also den Wert "1". Und so weiter. Für Befehle wie X, Y, Z etc. 
wird natürlich die äquivalente Funktion
1
float value = (float)strtod(valStart, &valEnd);

ausgeführt. In beiden Fällen, schreibt die Funktion in valEnd die Stelle 
des Endes der ausgewerteten Zahl der G-Code Zeichenkette hinein. Ist 
äußerst praktisch, weil man mit der Überprüfung
1
if(valEnd - valStart) {
2
...
3
}

sicherstellen kann, dass eine gültige Zahl erkannt wurde.

Jetzt kommt mein eigentliches Anliegen:

Ich möchte die Funktionen strtol und strtod ersetzen durch eine eigene 
Funktion um Kommazahlen ganz zu vermeiden. Diese soll dann bei X12.125 
z.B. 1940 zurückgeben (die Anzahl der Schritte). Die Auswertung und so 
weiter klappt alles. Jedoch bekomme ich es nicht hin, dass die Funktion 
die Endstelle in valEnd schreibt.

Bei mir sieht der Funktionsrumpf so aus (ähnlich wie strtol):
1
int decode(const char * str, char ** endptr);

Und in der Funktion wird am Ende, nachdem alles verarbeitet wurde 
folgender Code ausgeführt:
1
**endptr = *str;

Aufgerufen wird meine Funktion mit:
1
valEnd = valStart;
2
int value = decode(valStart, &valEnd);

Doch das Problem ist, dass valStart und valEnd immer gleich sind. Die 
Funktion arbeitet korrekt und gibt das richtige Ergebnis zurück. Jedoch 
kann ich die Überprüfung:
1
if(valEnd - valStart) {
2
...
3
}

nicht vornehmen, weil die Aussage jedesmal 0 ergibt. Ich habe die Sache 
mit Pointer und Pointer auf Pointer etc. nicht ganz drauf, deswegen seht 
es mir nach, wenn der Fehler offensichtlich ist und ich nicht drauf 
komme.
Ich hoffe ihr könnt mir helfen.

Vielen Dank im voraus und einen schönen Sonntag.

von DirkB (Gast)


Lesenswert?

Mit dem **endptr = *str; weist du ein char zu.
Du willst doch aber die Adresse von diesem Zeichen haben. Also str 
selber.
Darum
[c}*endptr = str;[/c]

von Tarek T. (tarek_t)


Lesenswert?

DirkB schrieb:
> Mit dem **endptr = *str; weist du ein char zu.
> Du willst doch aber die Adresse von diesem Zeichen haben. Also str
> selber.
> Darum
>
1
*endptr = str;

Ok, verstehe...ich benutze ja auch *str um die Chars auszuwerten. Hätte 
mir auffallen können.

Wenn ich deinen Vorschlag anwende, bekomme ich folgende Fehlermeldung:

error C2440: '=': 'const char *' kann nicht in 'char *' konvertiert 
werden

Lasse ich im Funktionsrumpf das const weg, so dass er wie folgt 
aussieht:
1
int decode(char * str, char ** endptr);

So klappt es! Jetzt ist mir nicht klar, warum in der strtol Funktion der 
Pointer als const char übergeben wird. Hat dazu jemand eine Idee? Habe 
den Funktionsrumpf nämlich einfach so übernommen.

Vielen Dank schonmal. So kann ich jedenfalls erst einmal weiter tüfteln.

von Karl H. (kbuchegg)


Lesenswert?

Tarek T. schrieb:

> Wenn ich deinen Vorschlag anwende, bekomme ich folgende Fehlermeldung:
>
> error C2440: '=': 'const char *' kann nicht in 'char *' konvertiert
> werden
>
> Lasse ich im Funktionsrumpf das const weg, so dass er wie folgt
> aussieht:
>
>
1
int decode(char * str, char ** endptr);
>


du hättest eher den endptr zu einem const char ** endptr machen sollen.

> So klappt es! Jetzt ist mir nicht klar, warum in der strtol Funktion der
> Pointer als const char übergeben wird. Hat dazu jemand eine Idee?

Natürlich.
Damit du die Funktion auch mit einem String-Literal benutzen kannst.

int value = (int)strtol("G08", &valEnd, 10);

denn dieser String IST konstant und die Funktion darf ihn nicht 
verändern. Das const macht genau diese Zusage. "Ich werde die Character 
selber nicht verändern".

von Tarek T. (tarek_t)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Natürlich.
> Damit du die Funktion auch mit einem String-Literal benutzen kannst.
>
> int value = (int)strtol("G08", &valEnd, 10);
>
> denn dieser String IST konstant und die Funktion darf ihn nicht
> verändern. Das const macht genau diese Zusage. "Ich werde die Character
> selber nicht verändern".

Ok, verstehe. Das macht bei strtol evtl. noch Sinn, da es dort vorkommen 
kann. In meinem Fall jedoch, wird als Argument nie eine konstante 
Zeichenfolge übergeben. Deshalb kann ich die const Definition im 
Funktionsrumpf getrost weglassen.

Danke für die Erklärung.

von Karl H. (kbuchegg)


Lesenswert?

Tarek T. schrieb:

> Ok, verstehe. Das macht bei strtol evtl. noch Sinn, da es dort vorkommen
> kann. In meinem Fall jedoch, wird als Argument nie eine konstante
> Zeichenfolge übergeben. Deshalb kann ich die const Definition im
> Funktionsrumpf getrost weglassen.

Kannst du.

Allerdings stellst du dir die falsche Frage. Bei const geht es (in einer 
Funktionsdefinition) immer darum, welche Zusage eine Funktion an den 
Aufrufer machen kann. Verändert deine Funktion den String? Höchst 
wahrscheinlich wird sie das nicht tun. Sie sucht ja nur etwas aus dem 
String heraus, das ist ja keine Veränderung. Daher kann diese Funktion 
die Zusage machen: Was immer du mir gibst, ich werde es nicht verändern.

An dieser Stelle ist das const also keine Forderung an den Aufrufer (du 
MUSST mir einen double geben), sondern eine Zusage! Und wenn Funktionen 
diese Zusage machen können, dann sollten sie das auch tun. Denn wenn du 
dann tatsächlich mal innerhalb der Funktion irrtümlich versuchst den 
String selbst zu ändern, dann klopft dir der Compiler auf die Finger.

Dieses const kostet dir nichts. Du musst es nur richtig machen. Aber für 
die Funktion und dessen Arbeit hat es bei dir keinerlei Auswirkungen, 
ausser dass du dir eine zusätzliche 'Sicherheitsebene gegen eigene 
Fehler' einziehst, die vom Compiler überwacht wird.

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.