Diese Diskussion wurde archiviert.
Es können keine neuen Kommentare abgegeben werden.
|
|
|
|
|
|
|
|
|
Wäre das nicht ein guter Einsatzbereich für FUSE?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Das hat gestern im IRC schonmal jemand gefragt. Ich verstehe allerdings ehrlich gesagt nicht, wieso das "Mounten" einen IRC-Kanals sinnvoller sein könnte als mit einer FIFO zu sprechen. Oder verstehe ich da was generell falsch, nachdem das jetzt schon das zweite Mal angesprochen wird? --verbose bitte. :-)
Achja, und was ich vergaß im Artikel: ii hat weniger als 500 Zeilen C-Code, ist also auch sehr übersichtlich. Das würde mit FUSE sicher nicht so bleiben.
--
There is no place like $HOME
|
|
|
|
|
|
|
|
|
|
|
|
|
> Achja, und was ich vergaß im Artikel: ii hat weniger als 500 Zeilen C-Code, ist also auch sehr übersichtlich.
Der Uebersicht zu liebe, werde ich in Zukunft jedes Programm auf 500 Zeilen zusammenquetschen ;-)
3b
Unknown: "If Linux doesn't have the solution, you have the wrong problem."
|
|
|
|
|
|
|
|
|
|
|
|
|
Nicht nur der Übersicht zuliebe, man denke an die total "überflüssige" Benutzerfreundlichkeit. Horror, was da an Code verschwendet wird...
|
|
|
|
|
|
|
|
|
|
|
|
|
Wieso fallen mir jetzt bloß die alten 1KByte Listings aus den CPC Zeiten ein, oder die Geschichten über Fraktale in Postscript? ;)
-- Case
|
|
|
|
|
|
|
|
|
|
|
|
|
Ohja, das war Klasse. Hat bei uns am Lehrstuhl mal jemand gemacht. Wenige kB Code, aber der Drucker rechnete Stunden an einem kleinen Bild. :-)
PostScript ist eh eine geile Sprache. Hatte nicht irgendwer mal einen httpd in PostScript geschrieben? (Ich such ja immer noch nach Ideen, wie ich einen in \TeX realisieren könnte. ;-)
--
There is no place like $HOME
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Sunday 27. November 2005, 23:50 MEW (#42)
|
|
|
|
|
FUSE ist crap. Wir verwenden 9P wenn schon denn schon.
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 11:33 MEW (#5)
|
|
|
|
|
ich wäre für ein generelles Verbot vom IRC Protokoll.
... so gäbe es die ganzen Botnets nicht.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ja klar, und ich heisse Fritz. Eine Botnet "Zentrale" (nein, nicht die des Taxi Sharia) kann ein Entwickler selbst realisieren. Ein Protokol für die Befehlsabwicklung über IRC braucht er sowieso, also fehlt da nur noch die Kommunikation.
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 13:01 MEW (#8)
|
|
|
|
|
Ich wäre für das Verbot vom WWW. Dann gibts keine gehackten Homepages mehr...
Und noch besser, wir hätten das Problem mit den doofen Benutzern gelöst, die z.B. so 'n Müll hier reinschreiben...
|
|
|
|
|
|
|
|
|
|
|
|
|
Ich wäre für ein generelles Verbot von Email, dann gibts kein Spam und Phishing mehr...
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 13:31 MEW (#10)
|
|
|
|
|
der typische unwartbare C-Rotz von Leuten, die vor 2 Wochen C gelernt haben. Das ist ja ein nettes Tool für zu Hause, aber veröffentlichen sollte man soetwas nicht. Buffer-Overflows konnte ich auf die Schnelle nicht finden, zumindest wird snprintf() genutzt. Das Prototypen ohne jegliche Benutzerfreundlichkeit (bzw. -tauglichkeit), ohne Fehlerprüfungen und kaum Features winzig klein sein können ist kein Wunder. Der Code eignet sich nur für einen Trojaner oder ähnliches aufgrund seiner Größe (obwohl es sicherlich noch kleiner ginge) aber kaum für etwas Sinnvolles.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dann guck dir mal bitte an, was wir so machen ich und anselm, dann wirst du feststellen, dass wir schon länger c machen. wenn du meinst jemand, der gerade c gelernt hat könnte ii schreiben, dann bist du offensichtlich ein moron.
|
|
|
|
|
|
|
|
|
|
|
|
|
Hmmm, ob ein Nicht-Debianer hier was anderes als "moron" geschrieben hätte? ;-)
nion: Ich finde es übrigens sehr beeindruckend, daß Ihr schon Monate bevor Ihr C gelernt habt, an ii programmiert habt. Das ist eine Leistung. (SCNR)
--
There is no place like $HOME
|
|
|
|
|
|
|
|
|
|
|
|
|
moron kenn ich garnicht aus dem debian umfeld :)
|
|
|
|
|
|
|
|
|
|
|
|
|
"Morons, I'm surrounded by morons."
-- Joel 'Espy' Klecker
da bist du wohl ein paar Jahre zu jung :)
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 14:38 MEW (#14)
|
|
|
|
|
Ich hab mir gerade mal das hier angesehen:
http://www.ngolde.de/download/nebi.c
Behebe doch mal bitte kurz alle Fehler darin, dann nehme ich mein Urteil vielleicht zurück.
|
|
|
|
|
|
|
|
|
|
|
|
|
das teil ist jahre alt und so eine kacke hör ich mir hier nicht an, troll dich.
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 20:36 MEW (#28)
|
|
|
|
|
Jahre? Der Code ist von letztem August. Es ging mir auch gar nicht darum zu zeigen, dass du letztes Jahr noch Fehler gemacht hast. Mein alter Code ist auch voller Fehler, wobei manche echt kritisch wären, wenn es Produktivcode wäre und andere eher theoretischer Natur sind und in der Praxis irrelevant sind. Gerade bei C lernt man eigentlich ständig dazu, vor allem bezüglich der Portierbarkeit des Codes, wenn man denn will.
Wenn dir einige Fehler in dem bisschen Code nach einigem zeitlichen Abstand nicht ins Auge springen, dann hast du eben noch nicht genug Erfahrung bzw. Wissen. Es geht aber nicht nur um richtig oder falsch. Code kann (je nach Anforderung) 100% das tun was er soll, aber letztlich grottenschlecht sein. Sprich: kaum wartbar, kaum portierbar, wenig erweiterbar. Bei 500 Zeilen merkt man das bei eigenem Code vielleicht noch nicht, aber versuch doch mal bei ii, Verschlüsselung oder IPv6-Support zu integrieren. Das kriegst du gebacken, keine Frage. Fragt sich nur wie hoch der Aufwand dafür ist bzw. wieviel dann komplett umgeschrieben werden muss.
Code nachträglich zu dokumentieren ist auch keine gute Idee. Erstens dokumentiert man dann nur was der Code anscheinend macht, anstatt zu dokumentieren was der Code machen soll und es dann implementiert. Zweitens ist der Anfangsaufwand irgendwann so hoch, dass gar nicht mehr an anfangen zu denken ist (Masochisten ausgenommen). Letztendlich geht ein grosser Vorteil der Dokumentation floeten, wenn man sie nachschiebt.
Ich bin ehrlich gesagt auch etwas allergisch gegen Minimal-Code, der dem achso bösen "Bloat" entgegengestellt wird. Nicht jeder "Bloat" ist sinnvoll, Fakt ist aber, dass vermeintlich "simple" Features überproportional Code verlangen. Zudem ist auch wenig sinnvoll "auf den Punkt" zu programmieren, sondern besser sich eine (kleine) Bibliothek zusammenzuschreiben, die zum einen wiederverwendet, zum anderen bei Bedarf leichter erweitert werden kann, da sie einem Gesamtkonzept folgt und kein ad-hoc Flicken-Code ist - so die Hoffnung. Letztendlich frisst Fehlerbehandlung viel Zeit und Code. Vieles von diesem Code kommt vielleicht nur selten oder nie zum Einsatz. Das ist es aber, was ein Code robust macht. Ein exit()
oder ein plattes GIGO ist nur in wenigen Fällen sinnvoll und vertretbar, ganz besonders, wenn die Software in einem Netzwerk zu Einsatz kommt und das ist seit ein paar Jahren indirekt quasi jede Software, die auf einem PC landet.
|
|
|
|
|
|
|
|
|
|
|
|
|
@nebi, ja august steht da, aber das war eine kleine (ich weiß garnicht mehr was) änderung, davon abgesehen ein schneller hack.
es geht auch garnicht darum solche features zu integrieren. es ist eine rc-1, die zeigt, was möglich ist und was machbar ist. ich bin habe auch ehrlich gesagt keine lust mich mehr über den code zu streiten, weil er a) gut ist und b) eine betaversion.
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 15:19 MEW (#20)
|
|
|
|
|
Schonmal ausprobiert was hier passiert, falls
gethostbyname() eine IPv6-Adresse liefert?
bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 15:29 MEW (#21)
|
|
|
|
|
Oder das hier, buffer stammt vom Server:
p = strchr(buffer, ' ');
*p = '\0';
Scheisse, was? Da bin ich echt erleichtert, dass Du schon über ein Jahr in C programmierst
|
|
|
|
|
|
|
|
|
|
|
|
|
du scheinst auf jeden fall hinter deinen worten zu stehen, deswegen postest du auch anonym. ich wette du hast in deiner jugend für deine scheisse zuviel aufs maul bekommen.
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 20:06 MEW (#27)
|
|
|
|
|
Bitte? Ich habe in meinem ganzen Leben noch von niemandem "eins aufs Maul" bekommen. Ich stamme aber zum Glück auch nicht aus dem Ghetto. Nach meinem Namen hat mich niemand gefragt, wieso sollte ich dann einen angeben? Du erinnerst mich an einen Vortragenden, der nach harscher Kritik dem "anonymen" Schnösel erstmal eine reinwürgen will. Ich bin kein Rechtschreibpedant, wer aber die gröbsten Regeln ignoriert, der schreibt eben solchen C-Code, wie du es tust. Du stehst doch dem CCC nahe oder nicht? Soweit ich weiss, respektiert
dieser Pseudonymität. Die stände dir bei solchen Beiträgen auch gut zu Gesicht. Da braucht man sich dann nicht noch 10 Jahre später über einen Ausraster ärgern. Zugegeben, ich hätte einen anderen Ton wählen sollen, aber im Kern stehe ich zu meiner Kritik.
|
|
|
|
|
|
|
|
|
|
|
|
|
was hat rechtschreibung jetzt mit code zu tun? und was ist konkret an dem code schlecht? und was daran spiegelt 2 wochen c kenntnisse wieder? und anonymität ist bei mir auch noch ein unterschied zu pseudonymität. einem pseudonym kann man oft ein gesicht oder einer person zuordnen, einem anonymen feigling nur eine ip. ich finde deine kritik zum einen nicht fundiert und zum anderen nicht konstruktiv und da stehe ich auch zu.
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 21:47 MEW (#32)
|
|
|
|
|
Ok, weil du so nett bist und ich ein Arschloch, hier eine unvollständige Liste in willkürlicher Reihenfolge. Die Logik habe ich nicht inspiziert und ursprünglich war auch nur mein erster Eindruck ausschlaggebend, d.h. Details habe ich jetzt erst bemerkt:
- nil, jeder C-Programmier kennt NULL, zur Not auch 0, was soll nil?
- getenv() kann auch NULL zurückgeben, wie sinnvoll ist ein Crash? Willst Du "irgendwann" mal all diese Stellen "verbessern"?
- strncpy() terminiert gar nichts, wenn der String größer oder so groß wie der Buffer ist.
- atoi(), na ja wer auf GIGO steht...
- Pfade dürfen nicht länger als 256 Zeichen sein? Schonmal überlegt wie lang so ein String mit UTF-8
wird, wenn er Japanisch, Chinesisch, Arabisch kodiert?
- enums sind gut, solche ohne (pseudo)-Namespace weniger (USER, CMD, CHAN, ARG).
- buf und _buf beides als globale Variablen und dann auch noch unkommentiert?
- viele Rückgabewerte werden nicht geprüft z.B. von write(), mkdir(), fopen().
- Underscores am Anfang von Funktionsnamen sind eine ganz schlechte Idee. Kollisionen sind vielleicht nicht fair und die eigene Schuld im Sinne des Standards aber zu erwarten. Außerdem häßlich; wozu?
- Kaum Rückgabewerte prüfen aber access() benutzen, wozu? mkdir() liefert auch EEXIST und man hat weniger race-conditions.
- Unsinniges casting "localtime((const time_t *) &t)" bringt keinerlei Vorteile, sondern nur Nachteile.
- Nahezu keinerlei Kommentare. Von den wenigen vorhandenen Kommentare sind fast alle völlig sinnlos. Das dokumentieren der Grammatik in proc_server_cmd() ist gut, man sollte sie dann aber auch implementieren.
- readl_fd() ist zwar leicht verständlich aber extrem ineffizient. Oh und übrigens, da ist ein ganz dicker fetter Buffer-Overflow. Falls dich höhere Programmlogik oder FIFO-Eigenschaften PIPE_BUF? retten (ich glaubs nicht), dann hast du vielleicht Glück, ändert aber nichts an dem miesen Code.
- Was ist überhaupt mit /../ in Pfaden bzw. Channel-Namen? Sieht mir nach GIGO mit hässlichen Nebenwirkungen aus. Es sollte ganz einfach aus dem Code und Kommentaren(!) klar ersichtlich sein, dass nichts passiert.
- const kann man nutzen, sollte man auch.
- wie Code beim Anwender kompiliert wird, ist eine Sache. Für den Programmierer mit GCC sollte -W -Wall -Wformat=2 Pflicht sein.
- snprintf() ist ja schön und gut, aber ist es wirklich OK, wenn abgeschnittete Strings Einfluss auf das Protokoll haben? Im User-Interface ist das eine andere Sache.
- Allgemein zu wenig Struktur: Wie schon jemand anders schrieb, globale Variablen gehören in ein gemeinsames struct, ganz besonders bei nichtssagenden Bezeichern. Wieso ein plattes strncmp()? Warum keine saubere Tabelle mit enums und Handlern?
- Strings sollten nicht an Ort und Stelle verarztet werden; selbst wenn man etwas Anfangs nur an zwei Stellen nutzt, macht es den Code sehr viel lesbarer und wartungsärmer, wenn man den Code sofort in eine wohlbenannte Routine auslagert.
- Nicht ein assert() oder vergleichbares; mutig.
- Letztlich ein monolithischer Haufen: sicher hättest du im nächsten Programm einige Routinen, die sich hier eigentlich ergeben sollten, verwenden können. So darfst du beim nächsten mal von vorn (mit Copy&Paste) anfangen.
- Hardkodierte Zahlen (z.B. 256), die sich eigentlich auf eine Variable beziehen sollten, es aber nicht tun. Normalerweise nutzt man ein Macro wie (sizeof (x)/sizeof (x)[0]).
- Unnötiges exit() z.B. in tcpopen(): Warum nicht -1 zurückliefern?
- int und size_t werden vermischt; hier kein Problem aber generell unsauber.
|
|
|
|
|
|
|
|
|
|
|
|
|
@nil, ob jemand nil oder NULL kennt, hängt vom Betriebssystem ab. Ist also eher Geschmackssache. Wer nicht weiß, was nil ist guckt halt ins define.
Ich hab keine Lust alles im Detail zu kommentieren (wenn du Lust drauf hast gern per Mail). Nur soviel, ein paar Sachen sind gut, danke für den Hinweis (es ist eine Beta-Version!!!!!), ein paar sind generell ok, treffen aber hier in dem Fall nicht zu, ein paar sind Geschmackssache (Kommentare z.b., der Code ist selbsterklärend). Ich habe nie behauptet, dass der Code perfekt[tm] ist, aber über ein paar Sachen lässts sich hier nur streiten. Bei ein paar Dingen hast du allerdings recht, danke für die Tips! Allerdings scheinst du nicht in der Lage zu sein deine Kritik von Anfang an konstruktiv zu gestalten. Eventuell hätte ein einfaches mir gefällts nicht gereicht und Bugs könnten per Mail diskutiert werden.
|
|
|
|
|
|
|
|
|
|
|
|
|
- Nicht ein assert() oder vergleichbares; mutig.
JUHU! Endlich mal ein Programm, welches nicht mit einer VOELLIG NICHTSSAGENDEN "assert() failed" Meldung ins Nirvana verabschiedet!
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Saturday 26. November 2005, 19:43 MEW (#36)
|
|
|
|
|
Wenn ein assertion failure nichtssagend ist, dann ist die assertion entweder nicht ausreichend dokumentiert (explizit oder implizit) oder du hast ganz einfach keine Ahnung von Programmierung. Darueber hinaus vergisst du das "Segmentation violation" (coredumps sind natuerlich wie ueblich deaktiviert) noch viel weniger hilfreich. Weiterhin habe ich nicht behauptet, dass der Code beim Endbenutzer nicht mit -DNDEBUG compiliert werden darf - darueber kann man lange diskutieren.
So oder so, man muss assert() sicher nicht benutzen, aber dann muss der Code so schluessig und ausreichend dokumentiert sein, dass keine Fehler auftreten oder wenn doch, die Ursache klar ist.
Ich denke mal, du bist kein Programmierer, sondern Endnutzer. Ich kann durchaus nachvollziehen, dass so ein "assert() ... failed" nerven kann und oft wird es auch falsch verwendet. Ich finde aber auch die Warnlampen im Auto nicht zum kotzen, nur weil mir die Leuchte selbst nicht weiterhilft. Ein Motorschaden oder aehnliches ist am Ende ein deutlich groesseres Problem.
|
|
|
|
|
|
|
|
|
|
|
|
|
Vorweg, ich finde es gut Kritik zum Code zu bekommen, da man sich dadurch nur selbst als Entwickler weiterentwickeln kann. Ich liebe auch ehrliche Kritik, die etwas ueberspitzt ist.
- nil, jeder C-Programmier kennt NULL, zur Not auch 0, was soll nil?
nil stammt aus der Plan9 Welt und ist ein stilistisches Element. Die C Erfinder verwenden nil und nicht NULL. Ken Thompsen hoechst persoenlich hat ueber lange Jahre den Plan9 und Unix C Compiler entwickelt und gewartet, der seit langer Zeit nil versteht (ist zugegeben kein ANSI/ISO Standard, aber man darf den C Erfindern ein Compiler-seitiges nil, was viel mehr Pruefungen zulaesst als ein NULL Makro, verzeihen). nil hat aufgrund des schoeneren Codes (keine haesslichen UPPERCASEMACROS) auch Einzug in Limbo gehalten.
- getenv() kann auch NULL zurückgeben, wie sinnvoll ist ein Crash? Willst Du "irgendwann" mal all diese Stellen "verbessern"?
Ist ein Punkt. Allerdings steht bei ii im Vordergrund aus moeglichst wenigen Code-Zeilen zu bestehen, denn diverse Ausnahmen abzudecken, steigert die Komplexitaet und damit die Fehleranfaelligkeit.
- strncpy() terminiert gar nichts, wenn der String größer oder so groß wie der Buffer ist.
Ja, in anderen Projekten verwende ich einen strlcpy()-Wrapper, welcher explizit bei buflen-1 den String terminiert. Fuer ii sollte man einen Wrapper von strncpy fuer diesen Fall in Erwaegung ziehen.
- atoi(), na ja wer auf GIGO steht...
In anderen Projekten verwende ich strtonum() von OpenBSD, ist aber leider keine ANSI C-konforme Funktion, sprich weniger portabel. Im Kontext ist das atoi() aber vernachlaessigbar, da auch nur in main() einmalig verwendet.
- Pfade dürfen nicht länger als 256 Zeichen sein? Schonmal überlegt wie lang so ein String mit UTF-8
wird, wenn er Japanisch, Chinesisch, Arabisch kodiert?
Solange solche 'corner cases' nicht real auftreten und von Usern gewuenscht werden, sehe ich keinen Grund Pfade laenger als 256 byte zu unterstuetzen.
- enums sind gut, solche ohne (pseudo)-Namespace weniger (USER, CMD, CHAN, ARG).
Wenn es nur eine enumeration gibt, wuerde es die Komplexitaet steigern, durch mehr unnoetigen Code.
- buf und _buf beides als globale Variablen und dann auch noch unkommentiert?
Ja, sie sind global um den Speicherbedarf moeglichst gering zu halten und durch fehlende lokalen Pendant-Definitionen unnoetig viele Zeilen zu produzieren. Die Namensgebung bei _buf ist verbesserungswuerdig.
- viele Rückgabewerte werden nicht geprüft z.B. von write(), mkdir(), fopen().
Ja, da besteht Nachholbedarf.
- Underscores am Anfang von Funktionsnamen sind eine ganz schlechte Idee. Kollisionen sind vielleicht nicht fair und die eigene Schuld im Sinne des Standards aber zu erwarten. Außerdem häßlich; wozu?
ACK
- Kaum Rückgabewerte prüfen aber access() benutzen, wozu? mkdir() liefert auch EEXIST und man hat weniger race-conditions.
Ja, danke fuer den Hinweis.
- Unsinniges casting "localtime((const time_t *) &t)" bringt keinerlei Vorteile, sondern nur Nachteile.
Das dient AFAIK lediglich dazu, um eine gcc Compiler-Warnung zu eliminieren.
- Nahezu keinerlei Kommentare. Von den wenigen vorhandenen Kommentare sind fast alle völlig sinnlos. Das dokumentieren der Grammatik in proc_server_cmd() ist gut, man sollte sie dann aber auch implementieren.
Die einzige kontextbehaftete Notwendigkeit zur Kommentierung ist eben diese Grammatik, da alle anderen Teile im Code trivial verstaendlich sind - aus meiner Sicht.
- readl_fd() ist zwar leicht verständlich aber extrem ineffizient. Oh und übrigens, da ist ein ganz dicker fetter Buffer-Overflow. Falls dich höhere Programmlogik oder FIFO-Eigenschaften PIPE_BUF? retten (ich glaubs nicht), dann hast du vielleicht Glück, ändert aber nichts an dem miesen Code.
Es ist ineffizient, die Ineffizienz aber im Kontext absolut vernachlaessigbar und ein non-issue. Der potentielle buffer overflow sollte aber drigend behoben werden.
- Was ist überhaupt mit /../ in Pfaden bzw. Channel-Namen? Sieht mir nach GIGO mit hässlichen Nebenwirkungen aus. Es sollte ganz einfach aus dem Code und Kommentaren(!) klar ersichtlich sein, dass nichts passiert.
Auch hier wurde absichtlich auf Ueberkomplexitaet verzichtet. Aber es besteht Nachholbedarf.
- const kann man nutzen, sollte man auch.
ACK
- wie Code beim Anwender kompiliert wird, ist eine Sache. Für den Programmierer mit GCC sollte -W -Wall -Wformat=2 Pflicht sein.
Ok
- snprintf() ist ja schön und gut, aber ist es wirklich OK, wenn abgeschnittete Strings Einfluss auf das Protokoll haben? Im User-Interface ist das eine andere Sache.
Haben sie nicht, da die verwendeten Buffer wesentlich groesser sind, als das Protokoll und der RFC zulaesst. Wenn was abgeschnitten wird, dann maximal userseitige Texteingaben (und der RFC schreibt max. 1K vor bis zur excess flood).
- Allgemein zu wenig Struktur: Wie schon jemand anders schrieb, globale Variablen gehören in ein gemeinsames struct, ganz besonders bei nichtssagenden Bezeichern. Wieso ein plattes strncmp()? Warum keine saubere Tabelle mit enums und Handlern?
Globale Variablen gehoeren im vorliegenden Fall aus Einfachheitsgruenden nicht in eine verkomplexitisierende struct. Im allgemeinen Fall gebe ich Dir dbzgl. aber Recht.
Zu den enum-gesteuerten Handlern sei anzumerken, dass ich in einer aelteren Entwickler-Version eine solche Handler-gesteuerte Struktur implementiert hatte (im darcs repo verfuegbar). Aber danach wieder verwarf, da durch die strncmp's Struktur etwa 30 Zeilen Code gespart werden konnten. ii versucht primaer(!) mit moeglichst wenigen Code-Zeilen auszukommen.
- Strings sollten nicht an Ort und Stelle verarztet werden; selbst wenn man etwas Anfangs nur an zwei Stellen nutzt, macht es den Code sehr viel lesbarer und wartungsärmer, wenn man den Code sofort in eine wohlbenannte Routine auslagert.
Die dann zwei weitere Zeilen zur Folge hat. Es gilt im Allgemeinen einen guten Mittelweg zwischen Struktur und der Komplexitaet des Problems zu finden. Und im Falle von ii ist das Problem trivial und deshalb eine ausgekluegelte Struktur vernachlaessigbar.
- Nicht ein assert() oder vergleichbares; mutig.
Mit Verlaub, assert() ist absoluter crap und hat in Code nichts verloren.
- Letztlich ein monolithischer Haufen: sicher hättest du im nächsten Programm einige Routinen, die sich hier eigentlich ergeben sollten, verwenden können. So darfst du beim nächsten mal von vorn (mit Copy&Paste) anfangen.
In anderen Projekten haben wir verschiedene Libraries, auf die wir im Falle von ii aus Gruenden der Minimalitaet und des Anspruches moeglichst geringer Abhaengigkeiten auf diese absichtlich verzichtet haben (ich erwaehnte bereits strl* und strtonum, darueber hinaus kaeme tokenize, etc. in Frage als Kandidaten).
- Hardkodierte Zahlen (z.B. 256), die sich eigentlich auf eine Variable beziehen sollten, es aber nicht tun. Normalerweise nutzt man ein Macro wie (sizeof (x)/sizeof (x)[0]).
Wenn man weiss wie lang ein Puffer ist, kann man durchaus seine Groesse im Code verwenden. Ich sehe keinen Grund statische Informationen nicht direkt zu verwenden. Und Makros sollten so wenig wie moeglich verwendet werden.
- Unnötiges exit() z.B. in tcpopen(): Warum nicht -1 zurückliefern?
ACK
- int und size_t werden vermischt; hier kein Problem aber generell unsauber.
ACK
Nochmals vielen Dank fuer Deine Hinweise.
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Monday 28. November 2005, 22:20 MEW (#44)
|
|
|
|
|
- nil stammt aus der Plan9 Welt und ist ein stilistisches Element.
nil kann man sich aus vielem herleiten (Lisp, Pascal, Objective-C(?)). Ich habe wohl auch gleich verstanden was damit gemeint war, da es mir aus den anderen Zusammenhängen bekannt war. Wenn ich C programmiere, benutze ich aber auch nicht
#define BEGIN {
#define END }
Der Autor der Bourne Shell hat das angeblich getan, aber auch große Namen können irren. Eine andere Sache ist, dass der Code dadurch erst bearbeitet werden muss, wenn man ihn in anderen Projekten verwenden will, wo man "nil" nicht sehen will oder es sich aus Konsistenzgruenden mit dem restlichen Code von selbst verbietet. Ich sag nur GLib: gchar, gint, glong braucht kein Mensch und sieht mit Verlaub Scheisse aus, aber wann immer ich Code zwischen GLib und dem Rest des Universums transferiere ist erst mal Style-Fixing angesagt. ii nutzt interessanterweise auch nicht konsequent "nil".
- keine haesslichen UPPERCASEMACROS
Bei Macros die "safe" sind, ist UPPERCASE wohl ueberfluessig, ansonsten ist es aber sehr nützlich diesen Hinweis zu haben. Besonders schön sieht das nicht aus, aber mit C gewinnt man auch keine Schönheitswettbewerbe.
- denn diverse Ausnahmen abzudecken, steigert die Komplexitaet und damit die Fehleranfaelligkeit.
Das stimmt wohl, aber Ausnahmen zu ignorieren macht den Code auch nicht robuster. Wenn man Ausnahmen nicht behandeln will, sollte man sie so früh wie möglich ausschließen.
- Ja, in anderen Projekten verwende ich einen strlcpy()-Wrapper, welcher explizit bei buflen-1 den String terminiert. Fuer ii sollte man einen Wrapper von strncpy fuer diesen Fall in Erwaegung ziehen.
Wenn man die Wahl hat, sollte man möglichst immer die gleichen Routinen verwenden, da sie sich bewährt hat und man mit ihnen vertraut ist. Von daher verstehe ich nicht, warum nicht einfach ein vorhandenes strlcpy() genutzt wird. Erst noch einen Wrapper für strncpy() zu schreiben, so simpel das sein mag, ist fehleranfällig und erhöht im weitesten Sinne das "Rauschen".
- In anderen Projekten verwende ich strtonum() von OpenBSD,
Ich habs mir gerade mal angesehen. Das Interface ist nicht gerade toll. Das Interface von strtoul()
ist da dank "endptr" wesentlich sinnvoller. Allerdings braucht man immer noch einen Wrapper um
diverse Spezialfälle abzufangen. Die Wahl der Basis will man strtoul() auch nicht unbedingt überlassen. Letztendlich ist "long" auch zu diffus für viele Zwecke; hier wäre es aber eine passende Alternative zu atoi().
- Im Kontext ist das atoi() aber vernachlaessigbar, da auch nur in main() einmalig verwendet.
Bei einem Kommandozeilen-Interface kann die "Schuld" zwar letztendlich immer auf den Benutzer schieben, aber der ist man meist auch selbst. Zumindest das gröbste sollte man rausfiltern. Wenn schon die wenigen Parameter, die vom Benutzer vorgegeben werden, nicht konsistent sind, wie will man dann intern sinnvoll Konsistenz erhalten und bewahren?
- Solange solche 'corner cases' nicht real auftreten und von Usern gewuenscht werden, sehe ich keinen Grund Pfade laenger als 256 byte zu unterstuetzen.
Ich weiss nicht, wo die magische 256 herkommt, aber Pfadnamen haben auf POSIX-System in der Regel ein minimales Limit von 1024 Zeichen, nicht 256. Für Dateinamen gilt gewöhnlich ein Limit von 256 Zeichen. Wenn man schon willkürliche Limits wählt, sollte man das nicht nach eigenem Gusto tun, sondern sich an den allgemeinen Konsenz halten. Da aber bei ii wohl nicht Performanz im Vordergrund steht, wird hier wirklich am falschen Speicher gespart.
- Wenn es nur eine enumeration gibt, wuerde es die Komplexitaet steigern, durch mehr unnoetigen Code.
Nö, man hat nur mehr Arbeit falls einige Enumerationen hinzukommen. Zudem hat man ganz schnell Namenskollisionen oder weicht auf krude Namen aus um diese zu verhindern. Außerdem kann man die Bezeichner meist etwas kürzer halten, wenn sie ein passendes Prefix haben, da sich die Bedeutung zusätzlich aus diesem "Pseudo-Namespace" ergibt. Wie sich dadurch die "Komplexität steigert" erschließt sich mir nicht.
- Unsinniges casting "localtime((const time_t *) &t)" bringt keinerlei Vorteile, sondern nur Nachteile.
Das dient AFAIK lediglich dazu, um eine gcc Compiler-Warnung zu eliminieren.
Es mag so gedacht sein, nur tut es das hier nicht.
Wenn in einem Prototype "const" auftaucht, gibt es sehr selten einen Grund den Parameter mit einem Cast zu versehen, der ein "const" ergänzt. Falls der Compiler wegen dem "fehlenden" const warnte, wäre das schlicht ein Bug im Compiler, aber kein Grund den Code zu verschlechtern. Mit jedem Cast riskiert man, dass zum falschen Typ gecastet wird, was bei Integer vs. Pointer üble Folgen haben kann. Compiler-Warnungen sieht man dann in der Regel nicht mehr, da man ja einen expliziten Cast verwendet. Wenn notwendig sollte man daher implizite Casts nutzen, in Form einer Funktion, die einfach den Parameter ge-cast-et zurückliefert. Ist an dieser Stelle aber völlig unnötig.
- Es ist ineffizient, die Ineffizienz aber im Kontext absolut vernachlaessigbar und ein non-issue.
Auf längere Sicht tut man sich aber keinen Gefallen, indem man ein Problem mit der Keule erledigt. In den meisten Fällen würde ich dir sicher recht geben, wenn es um Effizienz vs. Einfachheit geht. Aber einen FIFO kann man eigentlich öfters gebrauchen, besonders wenn man Programme schreibt, die Sockets nutzen. Jedes Zeichen einzeln per syscall aus dem Socket zu kratzen, ist schon etwas heftig. Bedenke das es sich hier nicht um "buffered I/O" handelt. Beispielweise ist getc() kein allzu großes Übel verglichen mit fgets() - es kommt natürlich auf die Implementierung an, da dort nicht jeder Aufruf einen Context-Switch verursacht. Für einen IRC-Client als Prototyp sicher noch akzeptabel, da hast du recht.
- Globale Variablen gehoeren im vorliegenden Fall aus Einfachheitsgruenden nicht in eine verkomplexitisierende struct.
Auch hier verstehe ich nicht was du mit "Komplexität" meinst. "globals.buf" ist wohl kaum komplexer als "buf". Es braucht mehr Tastenanschläge, dafür brauche ich aber nicht im Kontext suchen, ob "buf" vielleicht eine lokale Variable ist. Gleichzeitig funktioniert so ein "struct" dann auch als eine Art Namespace, d.h., man muss sich weniger blödsinnige Variablennamen ausdenken um Kollisionen zu vermeiden und es dient auch der impliziten Dokumentation. Meiner Meinung nach, kann man die Namen der "members" dann auch etwas schlichter halten, d.h. "buf" wäre OK, da sie ja immer mit einem Kontext versehen sind.
- Aber danach wieder verwarf, da durch die strncmp's Struktur etwa 30 Zeilen Code gespart werden konnten. ii versucht primaer(!) mit moeglichst wenigen Code-Zeilen auszukommen.
Ich denke, es gibt legimite Gründe die Zahl der Code-Zeilen zu verringern und solche die weniger sinnvoll sind. Die Redewendung "Eins nach dem Anderen." drückt es ganz gut aus. Wenn die einzelne Code-Zeile lesbarer und einfach zu verstehen wird, dann ist es völlig egal, ob sich die reine Zeilenanzahl dadurch verringert oder vergrößert. Ich habe lieber 100 Zeilen klaren Code als 10 Zeilen von einem IOCCC-Teilnehmer. Außerdem kann man ein Schema oft wiederverwenden, so dass Code der anfangs überladen aussieht auf Dauer dazu beiträgt, dass Code verständlich bleibt und mehr oder weniger "wie aus einem Guß" wirkt. Bei 500 Zeilen merkt man das noch nicht, aber wenn man ein "Werkzeug" eines Programmierers verstanden hat, liest sich der restliche Code, der dasselbe verwendet sehr viel leichter.
- Mit Verlaub, assert() ist absoluter crap und hat in Code nichts verloren.
Es gibt für viele Situationen sicherlich besseres als assert() und man kann es auch übertreiben, aber darauf verzichten will ich ganz sicher nicht.
In manchen Fällen kann man aber Compiler-Warnungen
nutzen oder für statische Bedingungen Compile-Fehler provozieren, so dass man dort kein assert() braucht.
- Wenn man weiss wie lang ein Puffer ist, kann man durchaus seine Groesse im Code verwenden. Ich sehe keinen Grund statische Informationen nicht direkt zu verwenden.
Ich aber. Welche der magische Zahlen bezieht sich denn auf welchen Puffer? Was ist denn, wenn diese Werte geändert werden sollen oder müssen? Wäre da nicht das 500-Zeilen-Argument, dann sähe ich da ganz schnell schwarz (oder rot, wenn es mein Programm wäre).
- Und Makros sollten so wenig wie moeglich verwendet werden.
Da vergisst du den Zusatz "so sinnvoll wie möglich". Für sehr viele Zwecke sind inline-Funktionen sicher die bessere Wahl, aber wenn man die Vor- und Nachteile von Makros verinnerlicht hat, dann bleiben einige sehr sinnvolle Anwendungen übrig.
#define LENGTH_OF_ARRAY(x) (sizeof (x)/sizeof(x)[0])
ist eine davon und auf jeden Fall besser als 100, 256 oder was auch immer zu benutzen. Das gilt auch auch für andere magische Zahlen. Es ist alle mal besser sich auf YADDA_YADDA zu beziehen als eine nichtssagende Zahl zu benutzen. Hier geht auch gar nicht darum, eine Möglichkeit zu haben, den Wert einfach zu ändern - was so leicht oft nicht ist, sondern vor allem wieder um Lesbarkeit und den Code verständlicher zu machen. Dort wo möglich sind als "static const" deklarierte Variablen gegenüber Makros klar die bessere Wahl.
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Wednesday 30. November 2005, 12:42 MEW (#45)
|
|
|
|
|
Hi, also im Grossen und Ganzen sind wir uns einig. Im Kontext von dem 500 Zeilen Programm haben wir einige unterschiedliche Auffassungen und an vielen Stellen hast Du wichtige Hinweise gegeben. In soweit vielen Dank fuer Deine Hinweise, vielleicht wirst Du den Code des naechsten RCs erneut reviewen wollen, um zu sehen was wir aus Deiner Kritik beruecksichtigen.
--garbeam
|
|
|
|
|
|
|
|
|
|
|
|
|
wenn du das problem mit dem code schnipsel auch noch erklären würdest, könnten wir auch drüber diskutieren.
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 21:54 MEW (#33)
|
|
|
|
|
Ich sehe nicht, wo garantiert wird, dass der String ein ' ' enthält. Darauf dass sich ein Server ans Protokoll hält, kann man sich wohl kaum verlassen. Daher kann strchr(buffer, ' ') NULL liefern, wodurch *p = '\0' undefiniertes Verhalten provoziert, regelmäßig in Form eines SIGSEGV.
|
|
|
|
|
|
|
|
|
|
|
|
|
Naja, ganz unrecht hat er nicht. Etwas mehr Kommentare (auch bei kleinen Programmen wichtig, IMHO) wären nicht schlecht gewesen, und der Gebrauch von Variablen namens i,j,k,n,p,x,y zeugt normalerweise von Leuten, die gerade ihre ersten Schleifen programmiert haben; das gleiche gilt für globale Variablen. Ich hätte die wohl zumindest in einen struct reingepackt (ein Pointer mehr in der Parameterliste ist auch nicht weiter schlimm).
Ansonsten kann ich nur sagen: Geile Idee, gut umgesetzt. Solche Programme gefallen mir!
tL -- ... I don't like it, but I guess things happen that way ... (J. Cash)
|
|
|
|
|
|
|
|
|
|
|
|
|
ja mag sein, was kommentare betrifft. über coding style kann man streiten... was variablen angeht, ich finde ersichtlich, wofür die gebraucht werden, der code ist einfach. ich streite mich hier auf jeden fall nicht über codingstyle mit leuten, die anonym posten (nicht du :)
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 14:25 MEW (#12)
|
|
|
|
|
... der typische, unlesbare Posting-Rotz von Leuten, die vor 2 Wochen das WWW entdeckt haben. Das ist ja ein nettes Posting für zuhause, aber veröffentlichen sollte man soetwas nicht.
Größere Rechtschreibfehler konnte ich auf die Schnelle nicht finden, zumindest wird "das" statt "daß" oder "dass" genutzt. Daß sich Postings ohne jegliche Formatierung, ohne nochmal durchzulesen und kaum Inhalt richtig scheiße lesen, ist kein Wunder. Das Posting eignet sich nur für ein Heise-Forum oder ähnliches aufgrund seines Niveaus (obwohl es sicherlich noch tiefer ginge), aber kaum für etwas Sinnvolles.
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 14:42 MEW (#16)
|
|
|
|
|
Mein Beitrag bezog sich auf den Artikel. Was möchtest Du genau mitteilen?
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 14:58 MEW (#17)
|
|
|
|
|
Mein Beitrag bezog sich auf Dein Beitrag. Was möchtest Du genau mitteilen?
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Friday 25. November 2005, 15:10 MEW (#18)
|
|
|
|
|
Ich möchte dir mitteilen, dass du ein "en" vergessen hast. Den Rest solltest du dir denken können, anderenfalls tust du mir leid. Einen schönen Tag noch!
|
|
|
|
|
|
|
|
|
|
Von Anonymer Feigling am Sunday 27. November 2005, 15:48 MEW (#38)
|
|
|
|
|
so ein schwachsinn. Das ist einfach nur von Plan 9 abgekupfert.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jo gibts:
http://www.r-36.net/ircc.tgz
|
|
|
|
|
|
|
|
|
|
|
|
|
nagut, weil so viele rumjammern mit getenv, weil ja bei leuten mit kaputten env-vars nicht gesegfaultet werden darf wird jetzt getpwuid benutzt :)
|
|
|
|
|
|