Hallo,
welches Busch oder welche andere Quelle würdet ihr empfehlen für die
Frage was man alles beachten muss wenn man weit verbreitete C++ Library
Funktionen benutzt. Z.B. wenn man Dateien öffnet und benutzt. Was ich
konkret hänge ist die Frage, wenn man eine Datei öffnet und einen File
Pointer bekommt der nicht der NULL Pointer ist, ist dann alles ok oder
muss man dann doch noch den Statuswert testen? Und was muss man sonst
noch beachten an exotischen Sonderfällen die auftreten könnten? (Datei
liegt auf einem Samba Share der ein ext3 oder NTFS Dateisystem hat,
dessen Rechte plötzlich..., und das Netzwerk hängt ein wenig, kommt aber
wieder, oder was anders extotisches. Das da Tipps gibt wie: Wenn man
einen File Handler bekommt, muss man doch noch dieses und jenes beachten
weil meist geht es gut aber es könnte doch sein dass...)
Einfach ein Kompendium über die Sachen die man beim professionellen
Programmieren beachten muss, die nicht Teil der Grundlagen-Vorlesung
waren.
Die bei einfachen Situationen egal sind, aber wenn man alle Spezialfälle
abdecken will braucht man mehr Hintergrund-Infos. Gerne auch speziell zu
Windows 7-10 und Visual C++.
Ich meine jetzt nicht so abstrakte Sachen wie "continuous integration"
oder "clean code" sondern konkret Fragen wie: Was muss man beachten wenn
man die lib-Funktionen benutzt und welche Methoden oder libs haben
welche Vor- und Nachteile (z.B. wenn es mehrere Methoden oder libs gibt
mit denen man auf Dateien zugreifen kann, um bei dem Beispiel zu
bleiben). Für ein altes Unix mit C hatte ich mal so ein Buch, aber was
gibt es für Windows 7-10 und Visual C++?
asd schrieb:> aber was gibt es für Windows 7-10 und Visual C++
Ich hab kein konkretes Buch, weil ich mir immer die Dokumentation
durchlese. Prinzipiell kann man sich dann nur auf das verlassen, was in
der Dokumentation garantiert wird. Der Rest kann funktionieren oder auch
nicht, also keine Annahmen einfach so oder durch ausprobieren treffen.
Bei deiner Frage musst du aber noch zwischen Bibliothek und
Betriebssystem unterscheiden. Bei z.B. C++, boost oder Qt sollte es bis
auf die Pfadsyntax unabhängig vom Betriebssystem sein. Wenn du jetzt
Win32 direkt verwendest, dann gilt das was Windows dort vorgibt.
Gerade in den Details, die für dich ja relevant sind, unterscheiden sich
die verschiedenen Libs aber durchaus. Deshalb wirst du wahrscheinlich
kein allgemeines Kompendium finden, wenn du dich nicht auf eine
Bibliothek einschränkst.
> Prinzipiell kann man sich dann nur auf das verlassen, was in> der Dokumentation garantiert wird.
Das ist klar. Diese Beschreibungen sind mir aber oft zu abstrakt, bzw.
ohne die nötige "Griffigkeit" in der Praxisrelevanz.
Z.B. kam die Frage auf, wenn fopen einen nicht-NULL-Pointer als File
Handler zurück liefert, ist dann alles ok? Oder gibt es doch
Spezialfälle in denen man noch weiteres beachten muss? Z.B. könnte was
in der Zeit passieren zwischen dem Aufruf von fopen und fclose.
Zugriffsrechte werden verändert, das Netzwerk zum Samba-Share hat einen
hänger, was auch immer. Vielleicht ist das egal, fclose fängt da ab.
Vielleicht gibt es einen Spezialfall in dem man als Programmierer
beachten. Die reine Beschreibung der lib gibt das nicht her (zumindest
nicht so dass ich mir sicher bin dass ich es verstanden habe)
Kann man einfach fclose aufrufen wenn man einen nicht-NULL-Pointer von
fopen bekommen hat (Konkretes Problem: In ganz seltenen Fällen crasht
das Programm beim fclose, und keiner weiß warum. Theorie: Die
Fehler-Abfang-Logik beachtet einen Sonderfall nicht)
Außerdem können beim Kunden exotische Konfigurationen auftreten die
keiner vorhersehen kann.
Da wäre ein Kompendium nicht schlecht das einen durch einen konkreten
Fall führt und z.B. ein Kapitel darüber hat was die Best Practises sind
beim Files auf- und zu machen. Und zwar nicht nur den einfachen Fall,
sondern auch für die praxisrelevanten Sonderfälle.
Klar, dazu braucht es einen Autor der Ahnung hat, und davon gibt es
nicht viele.
Natürlich kann so ein Buch nicht alle libs abdecken, aber wenn die
üblichen libs abgedeckt werden sind die bei Visual C++ dabei sind, wäre
das ein Anfang. Und vielleicht wird man in dem Buch ja auf andere
Methoden und libs hingewiesen die für manche Anwendungen besser sind.
asd schrieb:> fopen einen nicht-NULL-Pointer als File Handler zurück liefert,
Das ist kein "Handler", sondern ein "Handle". Ein "Handler" ist eine
Funktion o.ä., die etwas behandelt, ein "Handle" ist ein "Griff", ein
Ding, womit man etwas "anfassen" oder "manipulieren" kann, wie eben
Deine Datei.
Wenn Du davon ausgehst, daß die Netzwerkverbindung sehr instabil ist,
dann musst Du vor jeder Dateioperation die Gültigkeit der hinter dem
Handle steckenden Verwaltungsinformationen prüfen.
Die Funktionen der Standardlibrary gehen nicht von derartig kaputten
Umgebungen aus, Du wirst also mit den unterliegenden
Betriebssystemfunktionen hantieren müssen, wenn Du jeweils den
tatsächlichen Status der Dateiverwaltungsinformation prüfen willst. Da
da aber einiges an Caching dazwischen liegen dürfte, wird das noch nicht
mal besonders einfach.
In so einer Situation ist es am sinnvollsten, die Datei nur solange
jeweils geöffnet zu haben, wie tatsächlich auf Inhalte zugegriffen wird,
und sie sofort danach wieder zu schließen.
Rufus Τ. F. schrieb:> Wenn Du davon ausgehst, daß die Netzwerkverbindung sehr instabil ist,> dann musst Du vor jeder Dateioperation die Gültigkeit der hinter dem> Handle steckenden Verwaltungsinformationen prüfen.
Da die Probleme aber auch auftreten könnenen direkt nachdem man geprüft
hat und bevor oder während man den Handle nutzt ist das nicht wirklich
machbar. Das einzige was man machen kann ist "normale" Fehlerbehandlung
zu nutzen, also Rückgabewerte von fopen/fread/ferror und wenn nötig
errno auslesen.
asd schrieb:> (Konkretes Problem: In ganz seltenen Fällen crasht> das Programm beim fclose, und keiner weiß warum. Theorie: Die> Fehler-Abfang-Logik beachtet einen Sonderfall nicht)
Dann solltet ihr die Doku nochmal lesen und sicher stellen, dass eure
Fehler-Abfang-Logik korrekt ist.
Ein Handle ist eine dynamische Zugriffsnummer auf eine Systemresource
und kann vom System wieder verwendet werden. Solange das Handle als
invalid markiert ist bekommst du beim close INVALID_HANDLE zurück. Wenn
das System das Handle jedoch schon recycled hat kann es wieder gültig
sein und du schliesst ein anderes Systemobjekt.
Vermutung: Irgend jemand schliesst dein Handle und du greifst nach einer
gewissen Zeit darauf zu.
lemma 1:
Niemand kann von haus aus nach Schema-F den absolut richitgen Code
schreiben.
lemma 2:
Jeder Code, der nicht getestet ist, funktioniert nicht.
lemma 3:
lerning by doing is a must.
Reines Programmieren perfekt lernen zu wollen ist wie Chinesisch zu
lernen, ohne es je anzuwenden. Daraus folgt: Du wirst nie Chinesisch
können. Du kannst auch Kochen nicht über Rezepte lernen. In 21 Tagen zum
5-Sterne-Koch: Vergiss es!
Die Lösung deines Anspruches in Sachen Perfektion liegt in Deinem
iterierenden Bemühen, also Deinem Fleiß und Deine Ausdauer,
Problemstellungen erkennen, analysieren, erfassen und lösen zu können.
Danach die Lösung zu Perfektionieren, meint in puncto Tests,
Sicherheit, continous integration etc., alles das, was Du jetzt eben
nicht "sexy" findest. Aber das gehört unbedingt dazu. Perfektes
Programmieren lernen zu wollen, ohne den Bezug zu Software Engineering
haben zu wollen ist: infantil.
Backgroundinformation:
1. Geh in eine (Uni)Bibliothek. Verbring viel Zeit dort. Du wirst es nie
wieder missen wollen.
a. Such Dir verschiendeste Literatur von Bjarne Stroustrup z.B. zum
Thema "The C++ Programming Language" und anderes mehr von ihm.
b. Such Dir zum Thema Secure Programming for C and C++ Literatur,
studier sie begleitend zu Übungen und Kommunikation mit anderen (Foren,
Listen etc.)
c. Such Dir Literatur zu C und Richard Stallman, studier sie. Versuche
selbst den Unterschied herauszufinden zwischen Visual C++ und C++ und C.
d. Such Dir Bücher über Praktische C++ Programmierung. Siehe O'Reilly
Serien etc.
e. Such Dir Bücher über Effective C++ z.b. von Scott Meyers.
f. Such Dir Primers über C++ und versuche die darin enthaltenen
Beispiele zu programmieren.
g. Such Dir Bücher generell über Software Engineering, damit Du
Aufgabenstellungen überhaupt einmal erst richtig "behirnen" lernst.
h. Such Dir eine andere Programmiersprache aus z.B. LISP . Versuche die
Übungen, die Du mittels C++ geschafft hast mit LISP zu lösen.
i. Verschaff Dir generell mal einen Überblick über die Art und Vielzahl
von Programmiersprachen.
j. Lerne eine neue, weitere Programmiersprache.
k. Suche Dir Literatur über Noam Chomsky ... Generative Grammatik
Solltest Du nach dem Punkt K nicht von selbst die Punke L-Z finden,
kannst Du Dich gerne
an mich wenden, um sie Dir aufzulisten. Ich denke aber, wenn Du bis K
gekommen bist, erübrigt es sich. Dann bist Du auf solidem Weg in deinen
Beruf (=kommt von berufen sein).
Den seinen gibts der Herr im Schlafe. Angeblich. Doch das trifft, wenn
überhaupt nur auf die Wenigsten zu. Im Schweisse deines Angesichts
sollst Du Dir Dein Brot verdienen.
Gruß
Ein Freund
Allgemeines wird da nie alles abdecken, egal wie lange man in der
Biblio. rumhängt oder Bücher wälzt(wobei das aber generell nicht
verkehrt ist:-)
Ansatzpunkt würde ganz konkret bei den jeweiligen Funktionen nach
zuschauen.
z.B.: http://www.cplusplus.com/reference/fstream/fstream/open/
Da wird auch etliches zu den "Fehlerfällen" geschrieben.
Und dazu noch die zugehörige ähnliche Beschreibung der konkret
verwendete Funktion des verwendeten Compilers (inkl. der mitgelieferten
Std.Bibliothek)...
Es mag individuell unterschiedlich sein, aber für mich gilt:
Programmieren lernt man nicht aus Büchern.
Man kann (und sollte) die Grundlagen des Programmierens aus Büchern
lernen, aber richtig Programmieren lernt man nur durch eines:
Praxis.
Anstatt also in Bibliotheken rumzuhocken, solltest Du dich vor eine
Tastatur setzen und machen. Wenn Du das, was Du bis dahin weißt,
wirklich beherrschst, greifst Du wieder zu einem Buch.
asd schrieb:> Das ist klar. Diese Beschreibungen sind mir aber oft zu abstrakt, bzw.> ohne die nötige "Griffigkeit" in der Praxisrelevanz.
Das liegt daran, dass sie abstrakt genug sein müssen, um auch auf
Anwendungsfälle anwendbar zu sein, die der Autor in diesem Momemtn nicht
auf dem Schirm hatte.
> Z.B. kam die Frage auf, wenn fopen einen nicht-NULL-Pointer als File> Handler zurück liefert, ist dann alles ok?
In erster Linie ist dann zumindest nichts Offensichtliches falsch (d.h.
die Datei existiert oder kann erzeugt werden, du hast ausreichende
Rechte, usw.)
> Oder gibt es doch Spezialfälle in denen man noch weiteres beachten> muss? Z.B. könnte was in der Zeit passieren zwischen dem Aufruf von> fopen und fclose.
Unvorhergesehene Dinge können immer passieren. Im Extremfall schaltet
jemand einen beteiligten Rechner aus. Ob deine Software damit umgehen
können muss, hängt von deiner Anwendung ab.
Dazu kommt noch, dass Caching real existiert. Selbst, wenn ein fwrite()
gelingt, heißt das nicht, dass die Daten auch tatsächlich in der Datei
gelandet sind. Erst, wenn auch das fclose() erfolgreich ist, kannst du
davon ausgehen, dass alles erledigt wurde.
Daher der Ratschlag, die Datei nur möglichst kurz offen zu halten, wenn
die Netzwerkverbindung nicht sauber ist. Schnell ist anders, aber
"sicher, schnell, billig" geht halt nicht alles.
> Zugriffsrechte werden verändert, das Netzwerk zum Samba-Share hat einen> hänger, was auch immer.
Bei Netzwerkdateisystemen hängt es vom Dateisystem ab, welche
normalerweise existierende Garantien nicht mehr gelten. Es kann gut
sein, dass eine Datei während des Zugriffs für andere Nutzer gesperrt
ist (Locking), aber es muss nicht so sein. Hängt auch davon ab, was
deine Anwendung vorher angefragt hat.
Es gibt Windows-APIs für File-Locking, Record-based locking und so
Zeugs.
> Kann man einfach fclose aufrufen wenn man einen nicht-NULL-Pointer von> fopen bekommen hat (Konkretes Problem: In ganz seltenen Fällen crasht> das Programm beim fclose, und keiner weiß warum. Theorie: Die> Fehler-Abfang-Logik beachtet einen Sonderfall nicht)
Wenn du ein gültiges Handle von fopen() bekommen hast, dann kannst du es
an fclose() übergeben.
Genaueres gibt es nur, wenn du uns über den Crash informierst.
In deinem Fall geht es nicht um irgendwelche speziellen Libs, sondern um
die C-Standardbibliothek. Die ist nicht gerade unbekannt.
S. R. schrieb:> Erst, wenn auch das fclose() erfolgreich ist, kannst du> davon ausgehen, dass alles erledigt wurde.
Selbst dann nicht. Ob das OS und die Hardware ihre eventuell vorhandenen
Writecaches dann schon weggeschrieben haben ist an der Stelle alles
andere als sicher.
S. R. schrieb:> Wenn du ein gültiges Handle von fopen() bekommen hast, dann kannst du es> an fclose() übergeben.
Man kann nicht nur, man sollte sogar.
Frank _. schrieb:> Selbst dann nicht. Ob das OS und die Hardware ihre eventuell vorhandenen> Writecaches dann schon weggeschrieben haben ist an der Stelle alles> andere als sicher.
Stimmt, ein fclose() garantiert nur ein fflush(), aber kein fsync().
Hätte ich jetzt ehrlich gesagt nicht erwartet.
Also vorher unbedingt noch ein fsync() nachschieben, wenn die Daten
garantiert lesbar sein müssen - bessere Garantien gibt dann aber
tatsächlich nicht mehr.
Frank _. schrieb:>> Wenn du ein gültiges Handle von fopen() bekommen hast,>> dann kannst du es an fclose() übergeben.>> Man kann nicht nur, man sollte sogar.
Man kann auch ein anderes Handle an fclose() übergeben oder das
Betriebssystem das beim Programmende erledigen lassen. ;-)
Aber natürlich hast du recht. Ich meinte nur, dass ein von fopen()
übergebenes Handle niemals von selbst ungültig wird, also immer an
fclose() übergeben werden kann.
S. R. schrieb:> Stimmt, ein fclose() garantiert nur ein fflush(), aber kein fsync().> Hätte ich jetzt ehrlich gesagt nicht erwartet.>> Also vorher unbedingt noch ein fsync() nachschieben, wenn die Daten> garantiert lesbar sein müssen - bessere Garantien gibt dann aber> tatsächlich nicht mehr.
Das halte ich nur sehr bedingt für einen guten Rat.
Auf "normalen" Betriebssystemen darf man davon ausgehen, daß ein
fclose() die Daten auch irgendwann mal zuverlässig auf die Platte
bringt.
Wenn jetzt alle glauben, ihre Programme seien wichtiger als andere,
anfangen, ihren Disk-Caches zu mißtrauen und fsync()en, können die
Betriebssystemhersteller die Caches auch gleich weglassen.
Im Übrigen garantiert ein fsync() auf den Filedeskriptor einer offenen
Datei lediglich, daß die Datei-Daten auf der Platte gelandet sind.
Für den entsprechenden Directory-Eintrag gilt das nicht. Es kann also
immer noch passieren, daß zwar die Daten da sind wo sie hingehören, aber
der Verzeichniseintrag eben nicht (und die Datei damit auch kaputt ist).
Wenn man's ganz wasserdicht haben will, muß man (mit einem
entsprechenden Descriptor) das Verzeichnis ebenso fsyncen.
asd schrieb:> Konkretes Problem: In ganz seltenen Fällen crasht> das Programm beim fclose, und keiner weiß warum.
Hierbei dürfte es sich ziemlich sicher schlicht um einen (Programmier-)
Fehler beim Umgang mit dynamisch allokiertem Speicher bzw. einen
einfachen "Überschreiber" handeln.
fclose() ruft intern (u.a.) fflush() und free() auf. Wenn Ihr's
irgendwie geschafft habt (z.B. durch ein free() von Speicher, der nicht
dynamisch allokiert wurde oder durch Überschreiben von Speicher, der
Euch nicht gehört) diese Pufferaddressen zu verbiegen, kann es zu
solchen sporadischen Abstürzen kommen.
Ich würde mich an deiner Stelle mit valgrind (oder einem anderen
Programm, das solche Fehler aufdecken kann) daran machen, Euer Programm
kritisch zu untersuchen.
S. R. schrieb:> Dazu kommt noch, dass Caching real existiert. Selbst, wenn ein fwrite()> gelingt, heißt das nicht, dass die Daten auch tatsächlich in der Datei> gelandet sind. Erst, wenn auch das fclose() erfolgreich ist, kannst du> davon ausgehen, dass alles erledigt wurde.
Gerade das ist bei fclose NICHT der Fall. Nur was in der C-Lib u.U. noch
gebuffert ist, sollte dann dem OS übergeben worden sein.
Was das OS/die Treiber/die Hardware dann noch machen ist eine andere
Geschichte (unter Linux reicht sync/fsync u.U. nicht 1))
1) bspw. btrfs "Btrfs does not force all dirty data to disk on every
fsync or O_SYNC operation, fsync is designed to be fast."
https://btrfs.wiki.kernel.org/index.php/FAQ#Does_Btrfs_have_data.3Dordered_mode_like_Ext3.3F
Arc N. schrieb:> Gerade das ist bei fclose NICHT der Fall.
Das wurde mir bereits mitgeteilt und ich habe meine Aussage
diesbezüglich bereits revidiert. Drei Posts über deinem. Lesen!