Forum: Mikrocontroller und Digitale Elektronik [c] atoi mit 2d-Array bei uC


You were forwarded to this site from EmbDev.net. Back to EmbDev.net
von Tobi (Gast)


Lesenswert?

Hi da.

Wie liegt ein 2d-Array genau im Speicher?
Kann/Darf man z.B. atoi über eine Reihe laufen lassen (Terminiert mit 
0)?

Ich habe hier ein Projekt bei dem der alte Programmierer das an etlichen 
Stellen gemacht hat.
Ab und an haben wir Controller die nicht antworten.
Also habe ich nun einmal nachgeschaut und gesehen, dass es bei solch 
einem problematischen Controller am atoi() liegt.

Wenn ich die Daten in mein eigenes 1d-Array schaufel, läuft es durch.
Source läuft schon so seit 15Jahren...

Beispiel:
1
unsigned char ucInputData[10][8];
2
Input=(atoi((char *)&ucInputData[1][0]));

Was sagt Ihr dazu?
Tobi

von foobar (Gast)


Lesenswert?

> Wie liegt ein 2d-Array genau im Speicher?
>
> unsigned char ucInputData[10][8];

ucInputData[a][b] liegt an &ucInputData + a*8 + b

> Kann/Darf man z.B. atoi über eine Reihe laufen lassen (Terminiert
> mit 0)?

Solange die \0 da ist, kein Problem.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

kontrolliere das Programm auch auf Bereichsüberschreitungen / 
Buffer-Overflows. Nicht das im RAM im Nirwana gelesen bzw. geschrieben 
wird.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

foobar schrieb:
> Solange die \0 da ist, kein Problem.

Ich würde da auch mal in die atoi-Source schauen, ob das nicht auch bei 
unzulässigen Zeichen abbricht (was es eigentlich tun sollte). Die 
Chance, daß das dann trotz fehlender /0 niemals zurückkehrt, ist dann 
doch sehr gering.

Und ich würde mal nach Strings der Länge 8 bzw. einer Begrenzung auf 8 
Zeichen suchen...

Oliver

von Tobi (Gast)


Lesenswert?

Hi!

foobar schrieb:
>> Wie liegt ein 2d-Array genau im Speicher?
> ucInputData[a][b] liegt an &ucInputData + a*8 + b
Ja, okay - Dann sollte es ja passen.
Gerade auch ein Video dazu gefunden, was es auch gut erklärt:
https://www.youtube.com/watch?v=_j5lhHWkbnQ

>> Kann/Darf man z.B. atoi über eine Reihe laufen lassen (Terminiert
>> mit 0)?
> Solange die \0 da ist, kein Problem.
Ich selbst kam auf die Idee noch nicht, aber dann kommt das Problem 
nicht von der Ecke...

Veit D. schrieb:
> kontrolliere das Programm auch auf Bereichsüberschreitungen /
> Buffer-Overflows. Nicht das im RAM im Nirwarna gelesen bzw. geschrieben
> wird.
Leider hat der Controller (M16C) hier keine Debugging-Schnittstelle und 
ich muss mich mit Blinky und UART-Ausgaben zufrieden geben :)

Ich habe noch etwas entdeckt nachdem ich jedes Byte des Arrays 
ausgegeben habe. Es gibt z.B. auf [0][0] ein Nullbyte. Alle zwei 
fortlaufenden Bytes [0][1], [0][2]... ist dieses auch zu sehen.
So kann das mit atoi ja nicht klappen.

...Nur warum ab und an bei verschiedenen Controllern...
Verrückt (RAM kaputt?)

von Kevin M. (arduinolover)


Lesenswert?

Tobi schrieb:
> Wie liegt ein 2d-Array genau im Speicher?

Die liegen hintereinander im Speicher (zumindest wenn es static ist):
int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}};
Speicher -> 0 1 2 3 4 5

Tobi schrieb:
> Kann/Darf man z.B. atoi über eine Reihe laufen lassen (Terminiert mit
> 0)?

Wie bereits gesagt ist das kein Problem, solange die 0 wirklich da ist. 
Je nachdem wo das her komm ist das aber nicht unbedingt robust. Beim 
Empfangen kann ja auch mal etwas schief gehen.

Persönlich bevorzuge ich immer die Längenlimitierten String Funktionen 
wie z.B. strncmp statt strcmp. Ob es sowas für atoi gibt, weiß ich 
gerade nicht.

PS: Ich meine mich zu erinnern das atoi bei Zahlen, die zu groß sind, 
undefiniertes verhalten aufweist, vielleicht hat da ja noch wer anders 
Infos zu.

von Tobi (Gast)


Lesenswert?

Oliver S. schrieb:
> foobar schrieb:
> Ich würde da auch mal in die atoi-Source schauen, ob das nicht auch bei
> unzulässigen Zeichen abbricht (was es eigentlich tun sollte). Die
> Chance, daß das dann trotz fehlender /0 niemals zurückkehrt, ist dann
> doch sehr gering.
>
> Und ich würde mal nach Strings der Länge 8 bzw. einer Begrenzung auf 8
> Zeichen suchen...
Ok, ich schaue mal quer durch.

...Ein Debugger wäre doch soooo schön nun :)

von Oliver S. (oliverso)


Lesenswert?

Kevin M. schrieb:
> Wie bereits gesagt ist das kein Problem, solange die 0 wirklich da ist.
> Je nachdem wo das her komm ist das aber nicht unbedingt robust. Beim
> Empfangen kann ja auch mal etwas schief gehen.

Wenn die /0 fehlt, wird atoi aber über nicht wandelbare Zeichen 
stolpern, und dann (hoffentlich) 0 zurückgeben. Der Fall wird ja 
(hoffentlich) abgefangen.

Ich würde aber auch mal schauen, ob da die Länge des Input-String 
begrenzt wird (und das auf weniger als 8 Zeichen ;) )

Alles in allem stirbt die Hoffnung, wie immer, zuletzt.

Oliver

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

Tobi schrieb:
> Wie liegt ein 2d-Array genau im Speicher?
> Kann/Darf man z.B. atoi über eine Reihe laufen lassen (Terminiert mit
> 0)?

Allgemein darf in einem 2d-Array an beliebiger Stelle eine \0 im 
Speicher stehen. Nur für dein Beispiel, bei dem du offensichtlich zu 
wissen scheinst, dass in dem Array nur ASCII-Werten stehen können, macht 
die Frage überhaupt Sinn.

von Wilhelm M. (wimalopaan)


Lesenswert?

atoi() erwartet ein NTBS, das kannst Du erzwingen (sicherstellen), indem 
Du ucInputData[...][7] = `\0` setzt (`\0` ist das Sentinel, was bei NTBS 
erwartet wird).

Besser wäre natürlich ein
1
std::array<std::array<char, 8>, 10> ucInputData;

und ein
1
template<auto N>
2
int atoi(const std::array<char, N>&);

Ansonsten hat atoi() das große Problem, das atoi() `0` liefert, wenn es 
die Zeichenkette nicht parsen kann. Man kann also ein gültiges nicht von 
einem ungültigen Ergebnis unterscheiden. Das ist broken-by-design.

Besser wäre natürlich
1
template<auto N>
2
std::optional<int> atoi(const std::array<char, N>&);

von Dirk B. (dirkb2)


Lesenswert?

Tobi schrieb:
> Es gibt z.B. auf [0][0] ein Nullbyte. Alle zwei
> fortlaufenden Bytes [0][1], [0][2]... ist dieses auch zu sehen.
> So kann das mit atoi ja nicht klappen.
>
> ...Nur warum ab und an bei verschiedenen Controllern...
> Verrückt (RAM kaputt?)

Big- und Little-Endian Problem?

Wiviel Dezimalstellen hat denn die Zahl?

Oliver S. schrieb:
> Wenn die /0 fehlt, wird atoi aber über nicht wandelbare Zeichen
> stolpern, und dann (hoffentlich) 0 zurückgeben. Der Fall wird ja
> (hoffentlich) abgefangen.

Nein. Dann hört atoi() einfach auf und gibt den bereits ermittelten Wert 
zurück. Bei "8ung" wäre das 8.

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi schrieb:
> Ich habe noch etwas entdeckt nachdem ich jedes Byte des Arrays
> ausgegeben habe. Es gibt z.B. auf [0][0] ein Nullbyte. Alle zwei
> fortlaufenden Bytes [0][1], [0][2]... ist dieses auch zu sehen.
> So kann das mit atoi ja nicht klappen.

Wo kommen denn die Daten her?

von Tobi (Gast)


Angehängte Dateien:

Lesenswert?

Hi Ihr.

Erst einmal vielen Dank für das Mitdenken!
Ich habe einiges getestet und es scheint tatsächlich so zu sein, dass 
bei manchen frisch bestückten Controllern der RAM spinnt.

Ich habe das Problem-Array einmal gefüllt und ausgelesen.
Bei dem funktionierenden Controller kommen die korrekten Bytes zurück 
(wenn auch meine for/next irgendwo noch patzt :) ).

Bei dem defekten Controller kommen nur zwei, mal drei Bytes zurück.
Je nach dem wie oft ich starte... Auch mit LogicAnalyzer gecheckt.
Beide Ausgaben im Anhang.
1
unsigned int i;
2
unsigned char *pointbase;
3
unsigned char *pointa;
4
5
pointbase = &ucInputData[0][0];    //Pointer von Array start speichern
6
7
//32+4 * 8 -> 288bytes
8
9
for(i=0;i<250;i++)          
10
{
11
  pointa = pointbase + i;
12
  *pointa=i;            //RAM-Speicherstellen setzen 0-250
13
}        
14
15
for(i=0;i<250;i++)
16
{
17
  pointa = pointbase + i;
18
  uart_0_put_uart_mode(*pointa);  //RAM-Speicherstellen wieder zurück lesen und via UART ausgeben
19
} 
20
21
while(1);

Somit baue ich nun mal ein kleines Testprogramm, dass die Chips im 
Nullkraft-Sockel identifizieren kann.
Sch*** Bauteilemangel...

Nun endlich Feierabend.
Cu, Tobi

von Tobi (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Tobi schrieb:
>> Ich habe noch etwas entdeckt nachdem ich jedes Byte des Arrays
>> ausgegeben habe. Es gibt z.B. auf [0][0] ein Nullbyte. Alle zwei
>> fortlaufenden Bytes [0][1], [0][2]... ist dieses auch zu sehen.
>> So kann das mit atoi ja nicht klappen.
> Wo kommen denn die Daten her?
Von der UART und externen Programm.

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi schrieb:
> Ich habe das Problem-Array einmal gefüllt und ausgelesen.
> Bei dem funktionierenden Controller kommen die korrekten Bytes zurück
> (wenn auch meine for/next irgendwo noch patzt :) ).

Denke nicht: sollte ja mit 0 beginnen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi schrieb:
> Wilhelm M. schrieb:
>> Tobi schrieb:
>>> Ich habe noch etwas entdeckt nachdem ich jedes Byte des Arrays
>>> ausgegeben habe. Es gibt z.B. auf [0][0] ein Nullbyte. Alle zwei
>>> fortlaufenden Bytes [0][1], [0][2]... ist dieses auch zu sehen.
>>> So kann das mit atoi ja nicht klappen.
>> Wo kommen denn die Daten her?
> Von der UART und externen Programm.

Ok, aber das ist ja für den obigen Test irrelevant.

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi schrieb:
> (wenn auch meine for/next irgendwo noch patzt :) ).

Was soll das sein?

C99 liegt schon 23 Jahre zurück, also der alte Code und v.a. Dein 
Testprogramm sollte dann schon etwas moderner sein (Stichwort: 
Gültigkeitsbereich der Variablen).

von Forist (Gast)


Lesenswert?

Tobi schrieb:
> Beide Ausgaben im Anhang.

Ich sehe da nur zwei Pixelhaufen im JPG-Format. Soll man jetzt eine 
OCR-SW drauf loslassen, um irgendetwas damit anfangen zu können.

von Mark B. (markbrandis)


Lesenswert?

Wilhelm M. schrieb:
> Was soll das sein?
>
> C99 liegt schon 23 Jahre zurück, also der alte Code und v.a. Dein
> Testprogramm sollte dann schon etwas moderner sein

Die Aussage ist doch Quatsch. Wie der Themenersteller schon erwähnte, 
wurde der originale Sourcecode vor 15 Jahren geschrieben. Damals war C99 
sehr wohl der Stand der Technik.

von Wilhelm M. (wimalopaan)


Lesenswert?

Mark B. schrieb:
> Wilhelm M. schrieb:
>> Was soll das sein?
>>
>> C99 liegt schon 23 Jahre zurück, also der alte Code und v.a. Dein
>> Testprogramm sollte dann schon etwas moderner sein
>
> Die Aussage ist doch Quatsch. Wie der Themenersteller schon erwähnte,
> wurde der originale Sourcecode vor 15 Jahren geschrieben. Damals war C99
> sehr wohl der Stand der Technik.

Genau!
Du hast meine Aussage so gar nicht verstanden ...

von Tobi im Feierabend :) (Gast)


Lesenswert?

Wilhelm M. schrieb:
>> Ich habe das Problem-Array einmal gefüllt und ausgelesen.
>> Bei dem funktionierenden Controller kommen die korrekten Bytes zurück
>> (wenn auch meine for/next irgendwo noch patzt :) ).
> Denke nicht: sollte ja mit 0 beginnen.
Ja, theoretisch schon.
Ist aber Quick n dirty programmiert ohne zu checken ob ich das richtig 
gemacht habe ;)
Daher ist es für mich erst einmal nicht schlimm, wenn was nicht so ganz 
passt (Hatte einfach auch kein Bock mehr irgendwann).
Man sieht jedenfalls sehr gut, dass der merkwürdige Controller seine 
Arbeit in keinster Weise verrichtet.
Das reicht mir eigentlich schon zum ausfiltern.

Wilhelm M. schrieb:
> C99 liegt schon 23 Jahre zurück, also der alte Code und v.a. Dein
> Testprogramm sollte dann schon etwas moderner sein (Stichwort:
> Gültigkeitsbereich der Variablen).
Mein Testprogramm ist ein Debug-Teil des kompletten Programmes und auch 
in der alten WinXP-IDE geschrieben.
Da ändert sich also nichts.

Forist schrieb:
> Ich sehe da nur zwei Pixelhaufen im JPG-Format. Soll man jetzt eine
> OCR-SW drauf loslassen, um irgendetwas damit anfangen zu können.
Sehr konstruktiv!
Du bist auch der Meinung das NavyCIS die Pixelhaufen der Nummernschilder 
im wahren Leben so knackscharf hin bekommt oder? ;)
Spaß - Aber man kann sehr wohl das erkennen, was man erkennen muß.
Also bitte nicht so unnötig dazwischen quatschen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi im Feierabend :) schrieb:
> Wilhelm M. schrieb:
>>> Ich habe das Problem-Array einmal gefüllt und ausgelesen.
>>> Bei dem funktionierenden Controller kommen die korrekten Bytes zurück
>>> (wenn auch meine for/next irgendwo noch patzt :) ).
>> Denke nicht: sollte ja mit 0 beginnen.
> Ja, theoretisch schon.
> Ist aber Quick n dirty programmiert ohne zu checken ob ich das richtig
> gemacht habe ;)

Wie so oft, hast Du mal wieder nicht alles gezeigt!
Ich ging davon aus, dass das der Inhalt von main() ist. Wenn das so ist, 
dann ist das von Dir gezeigte Ergebnis eben nicht OK.

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi im Feierabend :) schrieb:
> Wilhelm M. schrieb:
>> C99 liegt schon 23 Jahre zurück, also der alte Code und v.a. Dein
>> Testprogramm sollte dann schon etwas moderner sein (Stichwort:
>> Gültigkeitsbereich der Variablen).
> Mein Testprogramm ist ein Debug-Teil des kompletten Programmes und auch
> in der alten WinXP-IDE geschrieben.
> Da ändert sich also nichts.

Warum schreibst Du auch Deinen Test-Code so grottig wie der 
ursprüngliche Autor? Das zeugt nicht unbedingt von Kompetenz.

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi im Feierabend :) schrieb:
> Also bitte nicht so unnötig dazwischen quatschen.

Halte mal den Ball flach!

von Tobi im Feierabend :) (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Wie so oft, hast Du mal wieder nicht alles gezeigt!
> Ich ging davon aus, dass das der Inhalt von main() ist. Wenn das so ist,
> dann ist das von Dir gezeigte Ergebnis eben nicht OK.
Wie so oft? Wie kommst Du darauf? Kennen wir uns?
Es ist mein Testcode am Anfang der Main.
Das Programm selbst hat ca. 5000 LOC.
Aber das ist ja auch nicht relevant, wenn man in dem kurzen Code snipped 
schon sieht, dass was gravierend nicht passt.

Wilhelm M. schrieb:
> Warum schreibst Du auch Deinen Test-Code so grottig wie der
> ursprüngliche Autor? Das zeugt nicht unbedingt von Kompetenz.
Weil man eben nach einem Tag herumstochern bei solch einem blöden 
Problem auch irgendwann keine Lust mehr hat.
Vor allem, wo soll das kleine Ding denn grottig sein?
Es zeigt in Kürze den Fehler auf.
Reicht doch erst einmal, wenn man auch mal Feierabend möchte...

Wilhelm M. schrieb:
> Halte mal den Ball flach!
Du hast schon gesehen, dass der Kommentar nicht an Dich ging oder?

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi im Feierabend :) schrieb:
> Wilhelm M. schrieb:
>> Wie so oft, hast Du mal wieder nicht alles gezeigt!
>> Ich ging davon aus, dass das der Inhalt von main() ist. Wenn das so ist,
>> dann ist das von Dir gezeigte Ergebnis eben nicht OK.
> Wie so oft? Wie kommst Du darauf?

Standard in diesem Forum.

> Es ist mein Testcode am Anfang der Main.
> Das Programm selbst hat ca. 5000 LOC.
> Aber das ist ja auch nicht relevant, wenn man in dem kurzen Code snipped
> schon sieht, dass was gravierend nicht passt.

Was hier nicht passt, ist:
1
unsigned char ucInputData[10][8];

Hier haben wir also 180 Bytes (auf dem Stack oder global, kann ich nicht 
entscheiden, weil Du mal wieder nicht alles zeigst).


Und im folgenden Snippet schreibst Du gnadenlose über das Ende des 
Arrays hinaus. Also, was sollen wir davon halten, wenn solche Basics 
nicht passen. Dann wird wohl auch an anderer Stelle was gravierend faul 
sein.
1
unsigned int i;
2
unsigned char *pointbase;
3
unsigned char *pointa;
4
pointbase = &ucInputData[0][0];    //Pointer von Array start speichern
5
//32+4 * 8 -> 288bytes
6
for(i=0;i<250;i++)          
7
{
8
  pointa = pointbase + i;
9
  *pointa=i;            //RAM-Speicherstellen setzen 0-250
10
}        
11
for(i=0;i<250;i++)
12
{
13
  pointa = pointbase + i;
14
  uart_0_put_uart_mode(*pointa);  //RAM-Speicherstellen wieder zurück lesen und via UART ausgeben
15
} 
16
while(1);

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi im Feierabend :) schrieb:
> Vor allem, wo soll das kleine Ding denn grottig sein?

Ich hatte Dir oben einen Hinweis gegeben, den Du ggf. übersehen oder 
nicht verstanden hast.

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi im Feierabend :) schrieb:
> Wilhelm M. schrieb:
>> Halte mal den Ball flach!
> Du hast schon gesehen, dass der Kommentar nicht an Dich ging oder?

Natürlich, und trotzdem schreibe ich was dazu. Es ist ein Forum und 
keine P2P-Kommunikation.

von Tobi im Feierabend :) (Gast)


Lesenswert?

Wilhelm M. schrieb:
>> Aber das ist ja auch nicht relevant, wenn man in dem kurzen Code snipped
>> schon sieht, dass was gravierend nicht passt.
> Was hier nicht passt, ist:
> unsigned char ucInputData[10][8];
>
> Hier haben wir also 180 Bytes (auf dem Stack oder global, kann ich nicht
> entscheiden, weil Du mal wieder nicht alles zeigst).
Ja, da hast Du recht.
Das habe ich nicht erwähnt.
Die 10/8 Bytes waren anfangs geschätzt, da über mehrere Defines 
deklariert und es zu dem Zeitpunkt auch nur um das atoi() ging.
Das hatte ich bei meinem Testcode dann jedoch nachgeschaut und meine 
Notiz "//32+4 * 8 -> 288bytes" hinzugefügt.
Sorry.

> Und im folgenden Snippet schreibst Du gnadenlose über das Ende des
> Arrays hinaus. Also, was sollen wir davon halten, wenn solche Basics
> nicht passen. Dann wird wohl auch an anderer Stelle was gravierend faul
> sein.
Wie gesagt, das passt schon :)
Wir haben 288byte Platz.

Wilhelm M. schrieb:
> Tobi im Feierabend :) schrieb:
>> Vor allem, wo soll das kleine Ding denn grottig sein?
>
> Ich hatte Dir oben einen Hinweis gegeben, den Du ggf. übersehen oder
> nicht verstanden hast.
Scheinbar habe ich das.
Welchen genau meintest Du?

Wilhelm M. schrieb:
> Tobi im Feierabend :) schrieb:
>> Du hast schon gesehen, dass der Kommentar nicht an Dich ging oder?
>
> Natürlich, und trotzdem schreibe ich was dazu. Es ist ein Forum und
> keine P2P-Kommunikation.
Kein Problem, aber auch das ist eine Unsitte in diesem Forum.
Plötzlich tauchen Leute auf, die über unnützes Zeug herum nörgeln ohne 
konstruktiv dazu beizutragen.
Ich kann ihm natürlich nicht unterstellen, dass er es nicht könnte, aber 
mit der Aussage das man mit einem OCR den Text lesbarer machen könnte, 
unterstreicht es nicht sehr.

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi im Feierabend :) schrieb:
> Wilhelm M. schrieb:
>>> Aber das ist ja auch nicht relevant, wenn man in dem kurzen Code snipped
>>> schon sieht, dass was gravierend nicht passt.
>> Was hier nicht passt, ist:
>> unsigned char ucInputData[10][8];
>>
>> Hier haben wir also 180 Bytes (auf dem Stack oder global, kann ich nicht
>> entscheiden, weil Du mal wieder nicht alles zeigst).
> Ja, da hast Du recht.
> Das habe ich nicht erwähnt.
> Die 10/8 Bytes waren anfangs geschätzt, da über mehrere Defines
> deklariert und es zu dem Zeitpunkt auch nur um das atoi() ging.
> Das hatte ich bei meinem Testcode dann jedoch nachgeschaut und meine
> Notiz "//32+4 * 8 -> 288bytes" hinzugefügt.

Kommentare sind irrelevant, da keine überprüfbare Verknüpfung zum Code 
besteht.

> Sorry.

Kein Thema.

von Wilhelm M. (wimalopaan)


Lesenswert?

Tobi im Feierabend :) schrieb:
> Wilhelm M. schrieb:
>> Tobi im Feierabend :) schrieb:
>>> Vor allem, wo soll das kleine Ding denn grottig sein?
>>
>> Ich hatte Dir oben einen Hinweis gegeben, den Du ggf. übersehen oder
>> nicht verstanden hast.
> Scheinbar habe ich das.
> Welchen genau meintest Du?

Z.B. Lokalität / Gültigkeitsbereich von Variablen, ...

von Peter D. (peda)


Lesenswert?

Wilhelm M. schrieb:
> Ansonsten hat atoi() das große Problem, das atoi() `0` liefert, wenn es
> die Zeichenkette nicht parsen kann. Man kann also ein gültiges nicht von
> einem ungültigen Ergebnis unterscheiden. Das ist broken-by-design.

Ich benutze daher sscanf(), das liefert die Anzahl der fehlerfrei 
gelesenen Werte zurück.

von Wilhelm M. (wimalopaan)


Lesenswert?

Peter D. schrieb:
> Wilhelm M. schrieb:
>> Ansonsten hat atoi() das große Problem, das atoi() `0` liefert, wenn es
>> die Zeichenkette nicht parsen kann. Man kann also ein gültiges nicht von
>> einem ungültigen Ergebnis unterscheiden. Das ist broken-by-design.
>
> Ich benutze daher sscanf(), das liefert die Anzahl der fehlerfrei
> gelesenen Werte zurück.

Das sind doch alles Krücken, die zuviel Aufwand verursachen (bei 
sscanf() in der Tat nur, wenn man >1 Format-Spezifizierer hat).

Wesentlich besser ist da

https://en.cppreference.com/w/cpp/utility/from_chars

was man auch gut verketten kann (oder man nutzt - wie oben schon 
geschrieben - std::optional<>, falls man Output-Parameter vermeiden 
möchte).

von Oliver S. (oliverso)


Lesenswert?

Wilhelm M. schrieb:
> std::

Wie häufig sind deine Ratschläge zwar prinzipiell richtig, helfen aber 
einem C-Programmierer nicht wirklich weiter. Und sehr vermutlich wird es 
auch hier um C gehen.

Oliver

von Wilhelm M. (wimalopaan)


Lesenswert?

Oliver S. schrieb:
> Wilhelm M. schrieb:
>> std::
>
> Wie häufig sind deine Ratschläge zwar prinzipiell richtig, helfen aber
> einem C-Programmierer nicht wirklich weiter. Und sehr vermutlich wird es
> auch hier um C gehen.

Naja, dass es um C geht, das steht ja schon in der Überschrift ;-)

Und wie immer erlaube ich mir den Blick etwas zu weiten.

Und eine C-Lib-Funktion wie `int atoi()` gehört einfach auf den Orkus 
der Geschichte: den Wert `0`, der zum gültigen Wertebereich eines `int` 
gehört, als Fehlerindikator zu verwenden, ist einfach nur Quatsch 
(wohlwissend, dass man natürlich zunächst prüfen kann, ob der String 
sicher aus `[+-0-9]` zusammensetzt).

von Dirk B. (dirkb2)


Lesenswert?

Peter D. schrieb:
> Wilhelm M. schrieb:
>> Ansonsten hat atoi() das große Problem, das atoi() `0` liefert, wenn es
>> die Zeichenkette nicht parsen kann. Man kann also ein gültiges nicht von
>> einem ungültigen Ergebnis unterscheiden. Das ist broken-by-design.
>
> Ich benutze daher sscanf(), das liefert die Anzahl der fehlerfrei
> gelesenen Werte zurück.

Als Ersatz für atoi gibt es strtol.
Das benutzt auch errno und liefert auch die Position, an der die 
Umwandlung stoppt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dirk B. schrieb:
> Peter D. schrieb:
>> Wilhelm M. schrieb:
>>> Ansonsten hat atoi() das große Problem, das atoi() `0` liefert, wenn es
>>> die Zeichenkette nicht parsen kann. Man kann also ein gültiges nicht von
>>> einem ungültigen Ergebnis unterscheiden. Das ist broken-by-design.
>>
>> Ich benutze daher sscanf(), das liefert die Anzahl der fehlerfrei
>> gelesenen Werte zurück.
>
> Als Ersatz für atoi gibt es strtol.
> Das benutzt auch errno und liefert auch die Position, an der die
> Umwandlung stoppt.

Stimmt nicht ganz:

- error wir benutzt, wenn ein range-error auftritt (C99 konform)
- bei anderen Fehlern wie nach wie vor `0` zurück gegeben.

Nur bei nicht C99-konformen Implementierungen wird errno == EINVAL 
gesetzt:

https://en.cppreference.com/w/c/string/byte/strtol

https://man7.org/linux/man-pages/man3/strtol.3.html

: Bearbeitet durch User
von Mikro 7. (mikro77)


Lesenswert?

Wilhelm M. schrieb:
>> Als Ersatz für atoi gibt es strtol.
>> Das benutzt auch errno und liefert auch die Position, an der die
>> Umwandlung stoppt.
>
> Stimmt nicht ganz:
>
> - error wir benutzt, wenn ein range-error auftritt (C99 konform)
> - bei anderen Fehlern wie nach wie vor `0` zurück gegeben.

Und:

If there were no digits at all,
strtol() stores the original value of nptr in *endptr (and
returns 0).  In particular, if *nptr is not '\0' but **endptr is
'\0' on return, the entire string is valid.

> https://man7.org/linux/man-pages/man3/strtol.3.html

Da gibt es auch ein Beispiel.

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.