Robert Bienert: String concat in c++

Beitrag lesen

Moin Martin!

In der zitierten Handbuchseite steht, dass snprintf zu ISO C99 gehört, was leider nicht alle Compiler unterstützen, während sprintf konform zu ANSI C ist, was wohl jeder Compiler versteht.

Ach so, also ist snprintf() noch etwas ziemlich neues. Kein Wunder, dass ich es nicht kenne.

Deshalb wird diese Funktion wohl bislang auch nicht von jedem C-Compiler angeboten, obwohl es wirklich sinnvoll wäre – angesichts der täglichen Meldungen über Buffer-Overflows in Software.

auf die [...] Windows API-Funktion wsprintf() zu, bei der ich als Programmierer ja auch dafür sorgen muss, dass mein Puffer groß genug ist.
Wie bekommt man denn dort dieses Problem in den Griff?

Ganz einfach durch eine worst-case-Abschätzung.

Also im Zweifelsfalle
char *buffer = malloc(sizeof(size_t) == 8 ? UINT64MAX : UINT32MAX)
;-)

Wenn ich Zahlenwerte mit xxprintf() ausgebe, sollte ich als Autor des Programmcodes wissen, in welchen Grenzen diese Zahlen liegen können - abgehakt.

OK, gebongt – float- und double-Werte sind insofern sogar recht praktisch, weil ich da in gewissen Grenzen den Platzverbrauch selbst vorgeben kann. Aber: Wieviele Stellen muss ich denn schlimmstenfalls für einen 64-Bit-Wert vorsehen bzw. welcher Programmierer weiß so etwas?

Im Fall von Strings ergibt sich die maximale Länge oft auch aus Beschränkungen, die im restlichen Programm irgendwo abgeprüft werden; in anderen Fällen gibt es strlen()

Leider fehlte dies im angesprochenen Beispiel. Ich weiß aus eigener Erfahrung, dass man sich auch in C mit dem Prinzip Hoffnung oft durchmogeln kann (allerdings nur in einem Bruchteil der Fälle verglichen mit z.B. PHP), ohne dass auch nur einmal der Buffer-Overflow zum Tragen käme.

oder die Möglichkeit, %s mit einer Längenangabe zu versehen.

Zu welchem Standard ist dann denn kompatibel?

Ich verstehe mit wachsender Programmier-Erfahrung nicht, wie es sein kann, dass solche Funktionen wie sprintf überhaupt noch als kleinster gemeinsamer Nenner zu einem Sprachstandard gehören, obwohl es deutlich sicherere Varianten gibt. IMHO ist die Stringbehandlung in C der Hauptgrund dafür, dass tonnenweise unsicherer C-Code geschrieben wurde und immer noch wird.

Hmm. Ich bin da wohl aus anderem Holz geschnitzt. Ich liebe die Freiheit, die C mir bietet, auch wenn sie gewisse Risiken birgt.

Die muss man erst einmal erblicken und dann unter Kontrolle bekommen. Insofern muss man vor den OpenBSD-Leuten echt den Hut ziehen: „Nur ein »remote hole« in der Standardinstallation seit über 8 Jahren!“

Oft geht mir sogar diese Freiheit nicht weit genug, so dass ich mich über Beschränkungen der Sprache an sich oder eines bestimmten Compilers ärgere (Stichwort Typkompatibilität).

Wie soll ich das denn interpretieren?

Vielleicht liegt's daran, dass ich jahrelang Assembler programmiert habe und da erst die _wirkliche_ Programmierer-Freiheit kennen und lieben gelernt habe?

Naja, da gibt es ja schon einen größeren Unterschied zwischen Assembler und C, vor allem zu C++. Am besten ist es, die Denkweisen und Paradigmen, die man von der einen Programmiersprache kennt, vollkommen über Bord zu werfen und sich in die Sprache einzudenken, mit der man gerade arbeitet.

Die allgemeine Sorgfaltspflicht obliegt schließlich immer dem Programmierer.
Wenn der allerdings nach eigener Aussage die ersten Gehversuche mit C macht ...

Oh, ich bitte um Entschuldigung. Das hatte ich tatsächlich schon wieder vergessen.

Tststs, und so etwas in diesem Forum, wo Programmieranfänger zuschauen. An dieser Stelle zum angesprochenen Beispiel: „The above code is dangerous. For your savety and those around you: Do not try this at home! - No really, don't!“ (Frei nach Braniac)

Noch schlimmer: Er benutzt nicht C, sondern C++, das ich sonst normalerweise meide wie der Teufel das Weihwasser, weil es die (im Gegensatz zu strengeren Sprachen wie z.B. Pascal) schon relativ laxen Syntaxregeln von C noch weiter aufweicht und mehr noch als C zu schlampigem Code verführt.

Das kann ich nicht bestätigen. Ich kann mittlerweile recht gut C++-Programmieren und ich finde, dass gerade die OOP (in C++) zusammen mit der STL gute Helfer bei der Vermeidung unnötiger Sicherheitslücken, Speicherlecks, … sind. Was ich z.B. zur Stringbehandlung sagte, gilt auch für dynamisch veränderliche Datenstrukturen: Das alles ist mit C++ deutlich sauberer, unkomplizierter und sicherer machbar.

Wobei man in C durchaus sehr sauberen und übersichtlichen Programmcode schreiben kann, wenn man sich ein wenig am Riemen reißt.

Selbstverständlich! Es kommt halt stark auf die verwendete Einführung in C an: Ich habe die Sprache damals mit einem Buch gelernt, indem der Autor ständig auf der Problematik mit Arrays, Strings und Pointern eindringlich eingegangen ist („dann ist das Verhalten der Funktion undefiniert“, …). Das hat mich ganz gut „erzogen“. Allerdings bezweifele ich, dass das für alle C-Programmierer gilt, zumal selbst große der Branche dämliche Fehler bis in die Doku schleppen: Bei Borland habe ich mal folgendes printf-/readdir-Beispiel gesehen:

  
#include <dirent.h>  
#include <stdio.h>  
  
DIR *dirp = opendir(".");  
  
while ((dp = readdir(dirp)) != NULL)  
    /* write out the files in this directory */  
    printf(dp->d_name);  
}  
(void)closedir(dirp);  

Das ganze wird natürlich bei %n im Dateinamen spaßig.

Viele Grüße,
Robert