Hallo,
Ganz einfach durch eine worst-case-Abschätzung.
Also im Zweifelsfalle
char *buffer = malloc(sizeof(size_t) == 8 ? UINT64MAX : UINT32MAX)
;-)
hehe... Mit "worst-case" meinte ich natürlich schon, dass auch programmintern gesetzte Limits berücksichtigt werden dürfen.
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 ...
Moment... 2^32 ist ungefähr 4E+09, 2^64 also rund 16E+18, normalisiert 1.6E+19 oder ±8E+18, also schlimmstenfalls 20 Stellen.
bzw. welcher Programmierer weiß so etwas?
Jeder, der sich nicht mehr "Anfänger" nennen muss. ;-)
[...] 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
Ja, gesundes Gottvertrauen (oder Gelassenheit durch Unwissenheit) ist auch eine Methode, und wie du schon andeutest, treten solche Fehler nur in einem Bruchteil der Fälle wirklich gravierend zutage. Aber mir wäre nicht wohl dabei...
oder die Möglichkeit, %s mit einer Längenangabe zu versehen.
Zu welchem Standard ist dann denn kompatibel?
Standard? Keine Ahnung, frag mich nicht solche Sachen. Mein Compiler (bzw. seine RTL) versteht das jedenfalls und setzt es korrekt um. Und darauf kommt es letzten Endes an.
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.
Die Freiheit oder die Risiken? Wie gesagt, die Freiheit weiß ich zu schätzen, und der Risiken bin ich mir größtenteils bewusst, weil ich maschinennah denke und intuitiv den zu meiner C-Anweisung gehörenden Assembler-Code vor Augen habe.
Insofern muss man vor den OpenBSD-Leuten echt den Hut ziehen: „Nur ein »remote hole« in der Standardinstallation seit über 8 Jahren!“
Das ist allerdings beachtlich. Mein Respekt!
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?
Beispiele:
Warning: Mixing Pointers to signed and unsigned char (mir doch egal, ich mach doch keine Arithmetik damit!)
DWORD n;
if (n==-1)
{ ... }
Warning: Constant out of range in comparison (Scheißcompiler! Du sollst nicht denken, sondern machen!)
BYTE *b;
DWORD *d;
d = b;
Error: Type mismatch (Herrje! Pointer ist pointer! Was ich damit mache, ist doch mein Problem!)
Noch mehr Beispiele?
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.
Nein, das kann ich nicht. Für mich ist Assembler die Königin aller Programmiersprachen (denn nur da habe ich _wirklich_ alles selbst in der Hand), und alles andere muss sich bei mir daran messen. Da kommt C zwar schon recht gut ran, aber manchmal eben nicht nah genug.
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.
Ja, aber gerade OOP neigt auch dazu, riesige Mengen Maschinencode zu produzieren, obwohl man das gleiche in klassischer prozeduraler Programmierung mit einem Bruchteil an Code hätte realisieren können.
Dazu kommt, dass meiner Ansicht nach gerade durch die Kapselung bei der OOP der Überblick über die Zusammenhänge verlorengeht - ist jedenfalls mein persönlicher Eindruck.
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.
Hmmm. Mir ist deutlich wohler, wenn ich Sachen wie die Speicherverwaltung den dafür zuständigen Betriebssystemfunktionen überlasse, anstatt irgendwelche C++-Konstruktionen zu verwenden, bei denen kaum jemand wirklich im Detail erklären kann, wie sie funktionieren.
Und was die Schlampigkeit bei C++ angeht: Der Punkt, der mich am meisten stört, wenn ich fremden Code lesen darf, ist das Deklarieren von neuen Variablen mitten im Programmcode. Reines C zwingt mich wenigstens noch dazu, alle Deklarationen am Anfang eines Blocks vorzunehmen, anstatt Kraut-und-Rüben-artig überall da, wo es mir gerade gefällt.
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“.
Sehr gut. Dann entwickelt man auch mit der Zeit ein Feeling für sauberen Programmcode. Leider trifft das nicht auf viele Programmierer zu.
while ((dp = readdir(dirp)) != NULL)
/* write out the files in this directory */
printf(dp->d_name);
Auaaa!
> Das ganze wird natürlich bei %n im Dateinamen spaßig.
Hä? Das wird bei fast allen Kombinationen mit '%' spaßig. Aber wofür steht %n?
Schönen Abend noch,
Martin
--
Die Zeit, die man zur Fertigstellung eines Projekts wirklich braucht, ist immer mindestens doppelt so lang wie geplant.
Wurde dieser Umstand bei der Planung bereits berücksichtigt, gilt das Prinzip der Rekursion.
[Schon Urlaubspläne?](http://lemmer-nl.privat.t-online.de)