Hallo,
ich habe mir eine Funktion geschrieben, die einen String übergeben
bekommt. In der weiteren Berechnung benötige ich nun aber auch die Länge
des Strings. Ist es möglich diese mit einem Befehl zu ermitteln oder
muss ich sie auch übergeben?
Für welche Programmiersprache willst du das denn wissen?
Ich gehe mal aus daß es sich um C handelt. Soweit ich mich beim K&R
erinnere ist das eine der ersten Funktionen die überhaupt behandelt
werden.
Wenn du das also nicht weisst, dann hast du noch nicht mal die ersten
beiden Kapitel deines C Buchs durchgearbeitet.
Wenn du mit so wenig Grundlagen versuchst zu programmieren kann das nur
mit Schiffbruch enden.
Also nimm oder besorge dir ein C Buch. Arbeite das durch, dann wird das
was.
Dein Array sieht im Speicher so aus:
'H','a','l','l','o',0
Die Null entweder selbst suchen (sehr praktisch wenn man den String
sowiso Buchstabe für Buchstabe abarbeiten muss) oder siehe Peter II
Einem C-Anfänger sei ohnehin angeraten sich mit den Fussangeln zu
beschäftigen die nullterminierte Strings mit sich bringen, auf dass sein
Produkt nicht irgendwann zum Gegenstand einer Sicherheitswarnmeldung
wird.
Schau ob deine Implementation strnlen() anbietet, aber sei gleichzeitig
behutsam mit willkürlichen Längenbeschränkungen, die sollten
dokumentiert werden wenn mit Strings gearbeitet wird die im Zusammenhang
mit Dateien oder Netzwerkverkehr stehen.
Eine einfache strlen()-Implementation kann man mit unbrauchbaren Daten
zB vom Netz oder aus einer manipulierten/fehlerhaften Datei schnell dazu
bewegen sehr hohen Ressourcenverbrauch und/oder einen Programmabsturz
herbeizuführen.
Andy D. schrieb:> Einem C-Anfänger sei ohnehin angeraten sich mit den Fussangeln zu> beschäftigen die nullterminierte Strings mit sich bringen, auf dass sein> Produkt nicht irgendwann zum Gegenstand einer Sicherheitswarnmeldung> wird.>> Schau ob deine Implementation strnlen() anbietet, aber sei gleichzeitig> behutsam mit willkürlichen Längenbeschränkungen, die sollten> dokumentiert werden wenn mit Strings gearbeitet wird die im Zusammenhang> mit Dateien oder Netzwerkverkehr stehen.> Eine einfache strlen()-Implementation kann man mit unbrauchbaren Daten> zB vom Netz oder aus einer manipulierten/fehlerhaften Datei schnell dazu> bewegen sehr hohen Ressourcenverbrauch und/oder einen Programmabsturz> herbeizuführen.
Immer diese Anspielungen ;-) http://xkcd.com/1354/
Ein Nullterminierter C-Stringist etwas vom Duemmlichsten, das man sich
vorstellen kann.Die Laenge braucht man ja eh sowieso. Weshalb sollte man
sich mit Code Zeit verplempern, wen mn sich die Lenge auch merken kann.
Sinnvollerweise verwendet man das Nullte Byte des Strings um die Laenge
festzuhalten.
Boahh schrieb:
>Sinnvollerweise verwendet man das Nullte Byte des Strings um die>Laenge festzuhalten.
Marek N. schrieb:
>Immer diese Anspielungen ;-) http://xkcd.com/1354/
Wow! Die Antwort kam 141 Minuten vor der Aussage.
Dachte so etwas gäbe es nur bei Douglas Adams!
Boahh schrieb:> Sinnvollerweise verwendet man das Nullte Byte des Strings um die Laenge> festzuhalten.
Bist du von BASIC Strings mit maximal 255 Zeichen gewohnt?
Warum nicht einfach konsequent immer die String-Länge als extra
Parameter übergeben und sich somit den Zeit-Verlust durch strlen und die
Sicherheitslücken durch Buffer-Overflows sparen? Oder, natürlich, C++
verwenden, welches eine String-Klasse hat:
1
voidfunction(std::stringmyStr){
2
std::cout<<"Mein string ist "<<myStr.size()<<" Zeichen lang.\n";
Jaja, dem schönen alten PASCAL nachflennen.
Ich bin gerührt.
Bei C muss man sich nun mal Gedanken über den Speicherverbrauch
machen. Besonders bei µCs mit knappen Resourcen ist das doch
sowieso erforderlich!
Passend dazu ein netter Artikel:
http://www.joelonsoftware.com/articles/fog0000000319.html
Nur wie man in C bei konstanten Strings nun besser als mit strlen
vorgeht hat bisher noch keiner gesagt, würde mich aber interessieren, da
ich selbst keine Lösung wüsste, außer Pascal-Strings und von Hand
zählen. Aber gegen Verzählen ist man dann auch nicht abgesichert?
Hallo Chris,
Chris schrieb:> ich habe mir eine Funktion geschrieben, die einen String übergeben> bekommt. In der weiteren Berechnung benötige ich nun aber auch die Länge> des Strings. Ist es möglich diese mit einem Befehl zu ermitteln oder> muss ich sie auch übergeben?>>
1
>voidfunction(chararray[]){
2
>...
3
>
Damit Du zur Abwechslung auch mal eine Antwort bekommst, mit der Du als
Anfänger etwas anfangen kannst:
Die Programmiersprache C (oder C++, die in dem Fall eine echte Obermenge
ist) übergibt an dieser Stelle faktisch nur einen Zeiger auf ein Array,
das Elemente vom Typ Char enthält. Du kannst also die Länge des Strings
nur dann erkennen, wenn sie aus dem String selber erkennbar ist, z. B.
wenn der String nullterminiert ist.
Wenn Du z. B. einen Aufruf machst
1
function("ABC");
, dann übergibt der Compiler faktisch
1
function(['A','B','C','\0']);
.
In diesem Fall kannst Du strlen() benutzen und es liefert 3 (das
versteckte Nullbyte wird nicht mitgezählt). Wenn Du aber an der Stelle
nur z. B. ein Array ['A', 'B', 'C'] übergibst, dann hast Du keine Chance
herauszufinden, wie lang das Array tatsächlich ist und brauchst einen
zusätzlichen Parameter für die Länge.
Falls Du C++ benutzt, so gibt es Arrayklassen, z. B. in der STL, wo die
Länge implizit übergeben wird.
Tschüß, Matthias
>Boahh schrieb:>> Sinnvollerweise verwendet man das Nullte Byte des Strings um die Laenge>> festzuhalten.>>Bist du von BASIC Strings mit maximal 255 Zeichen gewohnt?
Auf einem Controller ist ein String von 255 byte bereits jenseits von
vorstellbar. Was soll ich damit? Ein grosser LCD hat vielleicht 4x20,
heisst, ich bin mit 20 Byte zufrieden.
Nein, Strings zaehle ich nie, denn ich weiss ja die Laenge.
Matthias H. schrieb:> Damit Du zur Abwechslung auch mal eine Antwort bekommst, mit der Du als> Anfänger etwas anfangen kannst:
Das ist unfair, denn den wirklich sinnvollen Vorschlag bekam er ziemlich
zu Anfang:
Udo Schmitt schrieb:> Also nimm oder besorge dir ein C Buch. Arbeite das durch, dann wird das> was.
Zumal C++ hier auch nicht hilfreich ist, und das ebenfalls nur verwirrt:
Matthias H. schrieb:> , dann übergibt der Compiler faktischfunction(['A', 'B', 'C', '\0']);
Wie du selber weisst, wird eben bei einem String in C gerade nicht ein
Feld übergeben, sondern nur die Anfangsadresse.
Anstatt hier anhand von Gerüchten C zu lernen, wäre der gute Mann
wirklich mit einem guten Buch besser bedient - was er sich selber hätte
denken können.
Andy D. schrieb:> Schau ob deine Implementation strnlen() anbietet, aber sei gleichzeitig> behutsam mit willkürlichen Längenbeschränkungen, die sollten> dokumentiert werden wenn mit Strings gearbeitet wird die im Zusammenhang> mit Dateien oder Netzwerkverkehr stehen.> Eine einfache strlen()-Implementation kann man mit unbrauchbaren Daten> zB vom Netz oder aus einer manipulierten/fehlerhaften Datei schnell dazu> bewegen sehr hohen Ressourcenverbrauch und/oder einen Programmabsturz> herbeizuführen.
Also wenn sich jemand ein Netzwerkprotokoll oder Fileformat ausdenkt, in
dem nullterminierte Strings stehen und diese dann noch direkt ungeprüft
übernimmt, dann drucke ich dem gerne seinen Code aus und schlag ihm den
um die Ohren. Da wo das strlen() steht, muß schon lange geklärt sein,
daß da ein korrekt nullterminierter String steht, sonst kommt so oder so
Mist raus. strnlen() rettet da dann auch nicht mehr wirklich was.
Rolf Magnus schrieb:> Also wenn sich jemand ein Netzwerkprotokoll oder Fileformat ausdenkt, in> dem nullterminierte Strings stehen und diese dann noch direkt ungeprüft> übernimmt, dann drucke ich dem gerne seinen Code aus und schlag ihm den> um die Ohren.
warum? Und wenn dort dann 10GB Daten ankommen und dann erst eine \0 und
er dafür richtig Speicher anfordert wo soll das das Problem sein?
Was willst du denn Prüfen wenn das Protokoll nullterminierte Strings
vorsieht?
Man muss nur dafür sorgen, das der Speicher dafür ausreicht und wenn
nicht das das man sinnvoll abbricht. Das hat aber alles nichts mit
strlen zu tun.
Peter II schrieb:> Rolf Magnus schrieb:>> Also wenn sich jemand ein Netzwerkprotokoll oder Fileformat ausdenkt, in>> dem nullterminierte Strings stehen und diese dann noch direkt ungeprüft>> übernimmt, dann drucke ich dem gerne seinen Code aus und schlag ihm den>> um die Ohren.>> warum? Und wenn dort dann 10GB Daten ankommen und dann erst eine \0 und> er dafür richtig Speicher anfordert wo soll das das Problem sein?
Und wenn das \0 nicht da steht, lesen seine Stringfunkionen munter nach
dem Ende der Daten weiter im Speicher rum.
> Was willst du denn Prüfen wenn das Protokoll nullterminierte Strings> vorsieht?
Daß auch tatsächlich Nullterminierungen da sind.
Rolf Magnus schrieb:> Und wenn das \0 nicht da steht, lesen seine Stringfunkionen munter nach> dem Ende der Daten weiter im Speicher rum.
sie kann ja noch kommen.
> > Was willst du denn Prüfen wenn das Protokoll nullterminierte Strings> > vorsieht?> Daß auch tatsächlich Nullterminierungen da sind.
und wo hörst du auf mit lesen, wenn im Protokoll keine MAX Länge
definiert ist?
|
короткое троль schrieb:>>Boahh schrieb:>>> Sinnvollerweise verwendet man das Nullte Byte des Strings um die Laenge>>> festzuhalten.>>>>Bist du von BASIC Strings mit maximal 255 Zeichen gewohnt?>> Auf einem Controller ist ein String von 255 byte bereits jenseits von> vorstellbar. Was soll ich damit? Ein grosser LCD hat vielleicht 4x20,> heisst, ich bin mit 20 Byte zufrieden.>> Nein, Strings zaehle ich nie, denn ich weiss ja die Laenge.
Soso.
Tellerand und dahinter ist nicht?
Mein Board hier hat kein LCD und muss trotzdem Strings verarbeiten die
unter Umständen weit jenseits der 255 Zeichen sind.
Hey, ich brauch allein mehr um nen einzelnen Flash Block zu ändern.
Gibt halt nicht nur AVR und PIC.
Danke für die ganzen Antworten. Zu meiner Ehrenrettung möchte ich sagen,
dass ich kein ganz so blutiger Anfänger bin, wie der Frage vermuten
lässt. Ich habe nur seit Jahren ausschließlich embedded programmiert und
dadurch seit Ewigkeiten nicht mit Strings gearbeitet. Aber dank eurer
Antworten kam mir langsam wieder alles...
Meine Funktion bekommt einen String übergeben, der auf einem LCD
angezeigt wird. Dann gebe ich jedes Zeichen aus, bis der Inhalt 0 ist.
Den Inhalt gebe ich im Quellcode vor, den Speicher werde ich also nicht
überlasten. Ich könnte natürlich auch immer die Länge übergeben, aber so
gefällt es mir besser.
Nochmal danke!
Klaus Wachtler schrieb:> Unwahrscheinlich, daß es hier um Controller geht:>> Chris schrieb:>> return EXIT_SUCCESS;
Das kam nur durch den Beispielcode von Galileo Computing zustande.
Boahh schrieb:> Ein Nullterminierter C-Stringist etwas vom Duemmlichsten, das man sich> vorstellen kann.
Ich finde es genial.
Es macht die Verarbeitung sehr einfach und effizient.
Teilstrings lassen sich direkt parsen ohne ständige Kopier-Orgien.
Z.B. wenn ich ein Intel-Hex File einlese und binär in den Flash
schreibe.
Boahh schrieb:> Die Laenge braucht man ja eh sowieso.
Wozu denn?
Dann müßte ja mein Code haufenweise strlen() beinhalten, tut er aber
nicht. Das ist eine der am wenigsten verwendeten Funktionen.
Z.B. ein Parser bricht einfach ab, sobald er das 0-Byte erkennt. Wann
das ist, ist ihm sowas von egal.
Auch eine extra Längenangabe schützt überhaupt nicht vor Pufferüberlauf.
Das muß jeder Programmierer selber absichern:
1
if(idx>=sizeof(buffer))
2
returnERROR;
3
else
4
buffer[idx]=irgendwas;
Oder man hat ein OS, was dynamisch Speicher vergrößert, sobald die
aktuelle Länge überschritten wird. Das kostet natürlich massig Overhead.
Peter Dannegger schrieb:> Boahh schrieb:>> Ein Nullterminierter C-Stringist etwas vom Duemmlichsten, das man sich>> vorstellen kann.>> Ich finde es genial.> Es macht die Verarbeitung sehr einfach und effizient.
Wenn man es von der einfachen Implementierbarkeit der Standardbibliothek
absieht, ist eher das genaue Gegenteil der Fall. Siehe dazu z. B. den
Artikel auf joelonsoftware, zu dem oben jemand einen Link gepostet hat
und der den Unterschied zu "Pascal-Strings" erklärt (die zu Zeiten von
Turbo Pascal gängig waren, in neueren Sprachen der Pascal-Familie wie
Ada oder Delphi funktioniert das etwas anders und die Längengrenze von
255 Zeichen ist entfallen).
> Teilstrings lassen sich direkt parsen ohne ständige Kopier-Orgien.> Z.B. wenn ich ein Intel-Hex File einlese und binär in den Flash> schreibe.
Das ist aber "Zufall", weil das Format von Intel-Hexfiles eben extra so
entworfen wurde, daß es keine Binärdaten enthält. Würde man die Daten
noch mal zwischenpuffern und mit C-Stringfunktionen weiterverarbeiten,
so würde das höchstwahrscheinlich schiefgehen. Daher sollte man es
dringend lassen, in C-Strings allgemeine Daten abzulegen. In Sprachen,
die die Stringlänge unabhängig vom Inhalt speichern, kann man es dagegen
riskieren, ich habe das früher in Turbo Pascal und Delphi öfters
gemacht.
> Auch eine extra Längenangabe schützt überhaupt nicht vor Pufferüberlauf.> Das muß jeder Programmierer selber absichern:>
1
>if(idx>=sizeof(buffer))
2
>returnERROR;
3
>else
4
>buffer[idx]=irgendwas;
5
>
Das ist ein völlig anderes Problem, da geht es nicht um die fehlende
Längenangabe in Strings, sondern die fehlende Längenprüfung von Arrays.
Auch da bieten modernere Programmiersprachen Abhilfe.
In einem frühen Pascal-Compiler sind irgendwann Längenprüfungen für
Arrays eingeführt worden und man hat dann daraufhin die User gefragt, ob
man das Feature nicht aus Performancegründen abschaltbar machen sollte.
Die meisten haben sich dagegen ausgesprochen, weil man damit offenbar so
viele Fehler gefunden hat! Tatsächlich gehen die meisten
Sicherheitslöcher in C-Programmen einschl. Heartbleed auf solche oder
ähnliche Fehler zurück, die in moderneren Sprachen einfach kaum
passieren können (es sei denn, man schaltet die Prüfungen ab, soweit das
möglich ist).
> Oder man hat ein OS, was dynamisch Speicher vergrößert, sobald die> aktuelle Länge überschritten wird. Das kostet natürlich massig Overhead.
In dem Moment, wo die Laufzeitbibliothek/Standardbibliothek einer
Programmiersprache Funktionen für dynamische Strings enthält, kann man
auch die Speicherverwaltung auf die schnelle Allokation und Deallokation
kleiner Speichermengen optimieren. Gerade in Umgebungen, wo es nicht auf
jedes Byte ankommt, gibt es weitere Optimierungsmöglichkeiten, z. B. daß
man die Buffergröße und Stringlänge getrennt verwaltet, sodaß nicht jede
kleine Änderung an einem String Allokations-, Kopier- und
Deallokationsoperationen nach sich zieht.
"Oder man hat ein OS, was dynamisch Speicher vergrößert, sobald die
aktuelle Länge überschritten wird."
Die Speicherallokation wird vergrössert nicht der Speicher :)
Die einfachste strcpy-Implementation ist
while (*dest++=*source++);
Was soll da schon schiefgehen....
"Das ist aber "Zufall", weil das Format von Intel-Hexfiles eben extra so
entworfen wurde, daß es keine Binärdaten enthält."
Binärdaten sind ja auch nicht unbedingt das, was man in einem String
verarbeitet... Dafür bietet sich dann z.B. ein Array mit Längenangabe
an.
Peter II schrieb:> Andy D. schrieb:>> while (*dest++=*source++);>>>> Was soll da schon schiefgehen....>nichts
Richtig. Wenn der Programmierer aufpasst.
Außerdem gibts ja auch noch die _s Funktionen, welche genau sowas
verhindern sollen. Das da oben ist halt einfach mal ne echt schnelle und
schlanke Methode. C halt. Nur hat C keine Sicherheitsgurte.
> (dest ist bestimmt ein objekt mit überladenen Operatoren)
Komischer Humor...
cyblord ---- schrieb:> Außerdem gibts ja auch noch die _s Funktionen
Die sind ja die größte Lachnummer. In speziellen Fällen gelegentlich
"sicherer"...
Klaus Wachtler schrieb:> cyblord ---- schrieb:>> Außerdem gibts ja auch noch die _s Funktionen>> Die sind ja die größte Lachnummer. In speziellen Fällen gelegentlich> "sicherer"...
Narrensicherheit wirst du halt bei C nicht finden. Das macht die Sprache
nicht schlechter. Du kannst C nicht mit Pascal oder Java vergleichen.
Wer die Freiheit von C nicht erträgt, kann sie duch die Sicherheit von
höheren Sprachen aufgeben.
gruß cyblord
Chris schrieb:> Meine Funktion bekommt einen String übergeben, der auf einem LCD> angezeigt wird. Dann gebe ich jedes Zeichen aus, bis der Inhalt 0 ist.> Den Inhalt gebe ich im Quellcode vor, den Speicher werde ich also nicht> überlasten. Ich könnte natürlich auch immer die Länge übergeben, aber so> gefällt es mir besser.
Na wo ist dann das Problem ?
Du gibst selbst die Strings vor und niemand anders ändert die.
Ob Du das mit einer terminierenden 0 oder Längenangabe hoch 3
machst ist doch völlig egal.
Im schlimstem Fall erscheint Müll auf dem Display ;)
cyblord ---- schrieb:> Narrensicherheit wirst du halt bei C nicht finden.
Das erwarte ich gar nicht.
Ich arbeite viel mit C, und mag es (C++ natürlich lieber).
Ich mokiere mich nur über die Pseudosicherheit der ..._s-Funktionen.
Die verdecken mehr, als sie helfen.
cyblord ---- schrieb:> Außerdem gibts ja auch noch die _s Funktionen, welche genau sowas> verhindern sollen.
Unter einigen Betriebssystemen (ursprünglich OpenBSD, auch andere BSDs,
Mac OS X, Solaris, ...) gibt es strlcpy() und strlcat(). Die Funktionen
haben eine meiner Meinung nach außerordentlich gelungene Semantik, um
strcpy() und strcat() weitestgehend zu ersetzen. Auf Plattformen, wo es
sie nicht in der Standardbibliothek gibt, schreibe ich sie mir gerne
selber.
Siehe dazu auch http://www.courtesan.com/todd/papers/strlcpy.html .
Joachim Drechsel schrieb:> Na wo ist dann das Problem ?
Es gibt kein Problem mehr :)
Ich hatte das nicht mehr ganz auf dem Plan, dass hinter dem Array eine 0
steht. Das war die entscheidende Information für mich. :)
Es gab schon Programmfehler in der Geschichte bei denen es jahrelang
funktionierte weil hinter dem String irgendetwas allokiert und immer zu
dem Zeitpunkt auf 0 gesetzt war als dieser gelesen wurde...
Andy D. schrieb:> Es gab schon Programmfehler in der Geschichte bei denen es jahrelang> funktionierte weil hinter dem String irgendetwas allokiert und immer zu> dem Zeitpunkt auf 0 gesetzt war als dieser gelesen wurde...
Wenn es funktioniert ist es auch kein Fehler ;)
Joachim Drechsel schrieb:> Andy D. schrieb:>> Es gab schon Programmfehler in der Geschichte bei denen es jahrelang>> funktionierte weil hinter dem String irgendetwas allokiert und immer zu>> dem Zeitpunkt auf 0 gesetzt war als dieser gelesen wurde...>> Wenn es funktioniert ist es auch kein Fehler ;)
Nein, aber ein Bug.
Aber diese Zahl hilft dir nichts ohne die zugehörige Maßeinheit.
Ist XL jetzt 52? Oder 48? War es doch 92?
Also bleibt nichts übrig als anprobieren, d.h. strlen().
Andy D. schrieb:> Es gab schon Programmfehler in der Geschichte bei denen es jahrelang> funktionierte weil hinter dem String irgendetwas allokiert und immer zu> dem Zeitpunkt auf 0 gesetzt war als dieser gelesen wurde...
Es gibt allgemein erschreckend viele Programme, die nur zufällig
funktionieren.
Andy D. schrieb:> @scheppertreiber wenn das eine bewusste und dokumentierte Optimierung> ist ist es vielleicht kein Fehler, sonst schon ...
Ok, kann natürlich sein, daß es kein Fehler, sondern einfach nur
schlechter Code ist.