Hallo Forengemeinde,
habe ein Kommandozeilen-Programm unter Linux in C entwickelt und danach
auch mit MingW für Windows kompilieren können. Das Programm liest eine
Audio Datei im Waveformat und eine Textdatei ein und "filtert" mit
Kommandos aus der Textdatei die Audiodatei in 3 neue Dateien im
Waveformat.
Unter Linux kompiliere ich mit gcc 4.7.3 bzw. cross-kompiliere für
Windows mit dem i686-w64-mingw32-gcc 4.6.3. Das Programm läuft
anstandslos unter Linux und in der VirtualBox unter Windows 7. Es stürzt
ab auf mehreren anderen Windows 7 Computern mit einem lapidaten Popup
(siehe Anhang). Dies passiert auch, wenn ich das Programm direkt unter
Windows 7 mit MingW compiliere.
Jetzt zu meiner Frage: Wie kann ich am besten unter Windows den Fehler
einkreisen. Habe auf den Windows7 Computern keine Administrationsrechte
und damit auch keine Entwicklungsumgebung. Die Entwicklungsumgebung habe
ich in der virtuellen Windos-Installation. Dort stürzt das Programm aber
nicht ab.
Habe verzweifelt printf Aufrufe in den Programmfluss eingestreut und
vermeintlich die Absturzstelle eingekreist. Kommentiere ich sie aber aus
stürzt das Programm zu beliebig späterer Zeit ab. Habe mit Debugoptionen
(-g) und ohne Optimierung (-O0) übersetzt aber ich bekomme einfach keine
Fehlermeldung auf die Konsole.
Habt ihr eine Idee, wie ich das Programm (oder Windows) dazu zwingen
kann, mir mehr Informationen über den Grund des Absturzes zu sagen?
Übrigens hat das Fehler-PopUp einen Hinweis "Windows can check online
for a solution ...". Wenn man den anwählt kreist eine Weile die Sanduhr,
dann geht das Fenster ohne weitere Meldung zu - danke Microsoft!
Jede Hilfe ist willkommen.
Gerhard
Mit adplus den CallStack rausschreiben lassen, bei dem es crasht. Ist,
wenn ich mich richtig erinnere, Teil irgendeines Win SDKs. Ob das aber
admin Rechte braucht, weis ich nicht.
Klingt nach irgendeinem Stack Überschreiber. DIe zeigen gerne mal solche
Symptome.
Also: alle Array Zugriffe checken. Die sind die häufigste Ursache für
solche Dinge.
Wenn das Programm nicht allzugross ist und vor allen Dingen nicht noch
von zig anderen Libraries abhängt, kannst du ja mal den Source Code
posten.
Dirk B. schrieb:> Karl Heinz schrieb:>> Klingt nach irgendeinem Stack Überschreiber.> Evtl. ist auch der Stack zu klein.
habt ihr parat, wie ich dem gcc mitteile, dass er den Stack vergrößern
soll?
Ja, und den gdb.exe als ausführbares Programm (ohne Installation) hab
ich inzwischen gefunden. Versuche gerade, das Programm darin zum Laufen
zu bringen. Hab halt leider bisher selten direkt in ihm arbeiten müssen
sondern hab den ddd benutzt.
Danke schon mal
Gerhard
Gerhard Z. schrieb:> habt ihr parat, wie ich dem gcc mitteile, dass er den Stack vergrößern> soll?
das sollte keine Option vom Compiler sein. Beim starten eine threads
kann man die Stackgröße mitgeben. Aber wie es beim Hauptprogramm geht
kann ich nicht sagen.
Aber ich halte es für unwahrscheinlich das das Problem dort liegt, dann
müsste das verhalten immer Konstant sein.
Jetzt wird's ganz verrückt. Habe das Programm im Debugger laufen lassen.
Mit Parametersatz1 in der Textdatei läuft es durch ohne Fehler und
erzeugt alle Dateien ordentlich.
Mit Parametersatz 2 läuft es bis zum Ende durch (die letzten beiden
Befehle in der main sind ein printf und return 0;), das latzte printf
wird gemacht und die Dateien sind geschrieben aber es beendet mit
Fehlermeldung
[Thread 8812.0x1914 exited with code 0]
Program received signal SIGSEGV, Segmentation fault.
0x77bbfdaa in ntdll!RtlUnwind () from C:\Windows\SYSTEM32\ntdll.dll
Wenn ich beide Aufrufe direkt von der Kommandozeile aufrufe kommt der
ganz oben beschriebene Fehler beide male, die Dateien sind alle
angelegt, aber ohne Inhalt.
Im Debugger bekomme ich also Ergebnisse, außerhalb nicht. Ich weiß nicht
mehr weiter.
Noch irgend eine Idee?
Gerhard
nein, habe nur einen Thread (ich habe jedenfalls nichts explizit
angelegt und die Programmabfolge ist linear).
Das eigentliche Programm läuft auf einer ARM Hardware im Controlling
Bereich und ich habe jetzt zusätzlich ein Rahmenprogramm drumherum
geschrieben, welches die IOs der Hardware emuliert. Man kann jetzt also
den Programmablauf am PC simulieren (mit den Wavedateien als
Eingangsdaten). Das klappt ja auch unter Linux und unter Windows in
meiner virtuellen Box sehr gut, leider nicht auf richtiger
Windowshardware.
Ich würde das Programm gerne zeigen (obwohl es aus relativ vielen
Modulen besteh), habe aber ein Confidential Agreement unterschreiben
müssen und darf daher nichts rausrücken.
Sorry
Gerhard
Gerhard Z. schrieb:> nein, habe nur einen Thread (ich habe jedenfalls nichts explizit> angelegt und die Programmabfolge ist linear).
merkwürdig, damit sollte das Programm eigentlich immer das gleiche
Verhalten zeigen.
Sind alle Eingangsgrößen wirklich immer gleich oder gibt dinge die jedes
mal anders sind?
Unter Windows gibt es den dr.Watson, damit lässt sich ein dump
wegschreiben, wenn das Pogramm ein Fehler hat. Diese kann man dann
analysieren.
Man kann sogar einen eignen Crash-handler schreibem und dann einen
minidump vom ram erzeugen, das auswerten ist dann aber immer recht
mühselig.
http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplushttps://msdn.microsoft.com/de-de/library/windows/desktop/ms680360(v=vs.85).aspx
Nachtrag:
hast du die Möglichkeit das Programm mit dem Visual-Studio zu bauen?
Denn dort gib es kann auch eine remotedebugger. Den muss man nicht auf
den fremden System installieren.
Dann könntest du von einen Anderen PC mit dem VS remote auf den
Problem-Computer Debugger.
Gerhard Z. schrieb:> Jetzt wird's ganz verrückt. Habe das Programm im Debugger laufen lassen.> Mit Parametersatz1 in der Textdatei läuft es durch ohne Fehler und> erzeugt alle Dateien ordentlich.
Hmm.
Mit dem Microsoft Compiler wäre sowas unter anderem ein starkes Indiz
für die Verwendung einer nicht initialisierte Variablen. Könnte
allerdings immer noch ein Array Overflow sein.
> Im Debugger bekomme ich also Ergebnisse, außerhalb nicht. Ich weiß nicht> mehr weiter.
Abspecken. Zerlegen in Einzelmodule und einzeln rigoros testen.
Windows kann auch einen Crashdump erzeugen, der findet sich unter
c:\programdata\microsoft\windows\werfault\reportqueue\
Für jeden Absturz gibt es hier wiederum ein nach dem Prozess und
diversen anderen Dingen benanntes Verzeichnis, in dem der jeweilige
Crashdump zu finden ist.
Diesen Crashdump wiederum kann der Debugger des Visual Studio
verarbeiten, das sollte aber auch der Windbeutel (Windbg) hinbekommen.
Ob es einen Weg gibt, so etwas mit gdb auszuwerten, muss man die
gcc/gdb-unter-Windows-Fraktion fragen.
Früher* wurde ein Crashdump in Textform von drwtsn32 erzeugt, der
enthielt neben einem einfachen Stackdump auch ein Disassemblat der
Stelle des Absturzes.
Die "neuzeitlichen" Crashdumps sind zum Debuggen aber deutlich besser
geeignet, weil man sich mit ihnen auch lokale/globale Variablen,
Speicherinhalte etc. betrachten kann, ohne gleich auf der Assemblerebene
hantieren zu müssen -- sofern der verwendete Debugger das unterstützt.
*) bis einschließlich Windows XP / 2003
Karl Heinz schrieb:> Abspecken. Zerlegen in Einzelmodule und einzeln rigoros testen.
Ja, ich glaube, da muss ich durch. Habe an mehreren Stellen malloc im
Program um Platz zu scghaffen, um Binärdateien 1:1 in den Speicher
einzulesen. Habe jetzt mal einfach den doppelten Platz reserviert.
Programm stürzt zwar auch ab, aber jetzt sind die Ergebnisse
geschrieben. Wenn ich aber z.B. den 4-fachen Platz reserviere, dann
stürzt es wieder ab und alle Dateien haben 0 Byte.
Es wird schon was in die Richtung Array Überschreiben sein. Ich bin halt
kein Windows Entwickler und habe auf den Kisten keine Admin Rechte.
Alles in Richtung Visual Studio oder ähnliches ist lieb gemeint, hilt
mir aber im Moment nichts. Müsste erst ein eigenes Windows System
aufsetzen und entsprechende Toolchains installieren. Da scheu ich ein
bisschen vor zurück.
Blöd, dass sich der Fehler weder unter Linux noch im VirtualBox Windows
zeigt.
Hör für heute erst mal auf, vielen Dank erst mal für die vielen
Vorschläge.
Gerhard
Hallo Gerhard,
Gerhard Z. schrieb:> Ja, ich glaube, da muss ich durch. Habe an mehreren Stellen malloc im> Program um Platz zu scghaffen, um Binärdateien 1:1 in den Speicher> einzulesen. Habe jetzt mal einfach den doppelten Platz reserviert.> Programm stürzt zwar auch ab, aber jetzt sind die Ergebnisse> geschrieben. Wenn ich aber z.B. den 4-fachen Platz reserviere, dann> stürzt es wieder ab und alle Dateien haben 0 Byte.
Ohne Sourcecode kann man natürlich nicht viel sagen, aber vielleicht hat
das Verhalten Deines Programms auch etwas mit unterschiedlichen
Zeichensätzen zu tun. Linux nutzt meist UTF-8, Windows IMHO jedoch
UTF-16.
HTH,
Karl
Mit diesen Tools kann man einiges an Speicher-Bugs aufdecken:
http://duma.sourceforge.net/http://valgrind.org/ und http://valgrind.org/downloads/guis.html
Von Unix/Linux her kommend bietet Windows dem Programmierer ein paar
Fallstricke, mit denen der überhaupt nicht rechnet. Z.B. FILE-Pointer,
allozierte Speicherbereiche oder ähnliche "Handles", die man aus
irgendwelchen Libraries bekommt, im eigenen Code schließen/freigeben ...
und dann PENG
Hat denn jedes Mallc sein free? Und ist eventuell in der VM 32 Bit und
in dem echten System 64 Bit? Dann ist vielleicht irgendwo nicht bedacht
dass ein Pointer dann 8 Byte groß ist...
Der Fehler wird vermutlich auch in der Linux-Version enthalten sein und
sich dort nur nicht mit einem Absturz auswirken. Du könntest diese mal
in valgrind laufen lassen. Das zeigt dir recht ausführlich an, wenn du
irgendwo Unfug mit Speicher treibst. Vor allem kann es dabei auch auf
die Zeile verweisen, wo der Ursprung des Fehlers liegt, statt wie bei
einem klassischen Debugger nur auf die, wo er sich auswirkt.
Gerhard Z. schrieb:> Mit Parametersatz 2 läuft es bis zum Ende durch (die letzten beiden> Befehle in der main sind ein printf und return 0;), das latzte printf> wird gemacht und die Dateien sind geschrieben aber es beendet mit> Fehlermeldung>> [Thread 8812.0x1914 exited with code 0]>> Program received signal SIGSEGV, Segmentation fault.> 0x77bbfdaa in ntdll!RtlUnwind () from C:\Windows\SYSTEM32\ntdll.dll
Dann wird wohl in der ntdll nach Programmende etwas erneut freigegeben.
> Wenn ich beide Aufrufe direkt von der Kommandozeile aufrufe kommt der> ganz oben beschriebene Fehler beide male
Ja, dass kenn ich. Valgrind hilft mir bei solchen Problemen immer.
> die Dateien sind alle> angelegt, aber ohne Inhalt.
Suche im current working directory, dem Programmverzeichnis, dem
Zielverzeichnis und den Dokumenten nach Dateien mit kryptischen namen,
sind möglicherweise versteckt. In diesen temporären Dateien könnte sich
der fehlende inhalt befinden.
PS: Wie öffnest und schliest du die Dateien (funktionsname)
Gerhard Z. schrieb:> Ich bin halt> kein Windows Entwickler und habe auf den Kisten keine Admin Rechte.> Alles in Richtung Visual Studio oder ähnliches ist lieb gemeint, hilt> mir aber im Moment nichts. Müsste erst ein eigenes Windows System> aufsetzen und entsprechende Toolchains installieren. Da scheu ich ein> bisschen vor zurück.
und warum? Wenn man für Windows Programm entwickelt sollte man zumindest
auch eine passende Umgebung für die Fehlersuche haben.
In einer VM einfach mal das Setup zu starten kann ja wohl nicht so
schwer sein. Vermutlich ist das Problem mehr das Projekt mit dem VS zu
übersetzen. Aber man hat den Vorteil das ein andere Compiler eventuell
das Problem anders darstellt und man so auf die Lösung kommt.
Rolf Magnus schrieb:> Der Fehler wird vermutlich auch in der Linux-Version enthalten sein
ja, nehme ich auch an, von daher ist valgrind ein guter Tip. Hab ich
noch nie benutzt, aber irgendwann ist immer das erste Mal.
> Hat denn jedes Mallc sein free?
Nein, es gibt kein free; der Speicher wird bis zum Programmende benutzt
und ich bin davon ausgegangen, dass das Betriebssystem beim Terminieren
des Programms den Speicher freigibt. Ist da mein Denkfehler?
> Wie öffnest und schliest du die Dateien?
fp = fopen(FileName, "rt");
fclose(fp);
Danke für die rege Beteiligung
Gerhard
Gerhard Z. schrieb:>> Wie öffnest und schliest du die Dateien?> fp = fopen(FileName, "rt");> fclose(fp);
bzw.
fp = fopen(FileName, "rb");
für die Dateien im wav-Format
Gerhard
Karl Käfer schrieb:> aber vielleicht hat das Verhalten Deines Programms auch etwas mit> unterschiedlichen Zeichensätzen zu tun. Linux nutzt meist UTF-8, Windows> IMHO jedoch UTF-16.
Was da verwendet wird, hängt von den Compilereinstellungen und.
verwendeten Laufzeitbibliotheken ab; es können sowohl Unicode als auch
MBCS verwendet werden (MBCS fasst UTF-8 und das Verwenden von
8-Bit-Codepages zusammen, für Konsolapplikationen ist CP850 bzw. CP437
üblich).
Christian R. schrieb:> Und ist eventuell in der VM 32 Bit und in dem echten System 64 Bit? Dann> ist vielleicht irgendwo nicht bedacht dass ein Pointer dann 8 Byte groß> ist...
Das entscheidet der Compiler. Ein 32-Bit-Programm ist ein
32-Bit-Programm, auch wenn es unter einem 64-Bit-OS ausgeführt wird.
Sofern also das gleiche Binary in der VM und in der "Testumgebung"
verwendet wird, kann das nicht die Ursache sein.
Wenn das Programm hingegen mit unterschiedlichen Compilern übersetzt
wird, gibt es viele interessante Möglichkeiten.
Gerhard Z. schrieb:> Nein, es gibt kein free; der Speicher wird bis zum Programmende benutzt> und ich bin davon ausgegangen, dass das Betriebssystem beim Terminieren> des Programms den Speicher freigibt. Ist da mein Denkfehler?
Nein, einen Crash in ntdll ergibt so ein Speicherleck nicht.
Das gibt maximal diverse Ausgaben auf der Debugkonsole, was aber nur
geschieht, wenn man einen Compiler mit entsprechender
Debug-Laufzeitumgebung und diversen Speichertests zur Laufzeit
verwendet.
Ohne aktiver Debugkonsole sieht man davon nichts.
Peter II schrieb:> Wenn man für Windows Programm entwickelt sollte man zumindest> auch eine passende Umgebung für die Fehlersuche haben.>> In einer VM einfach mal das Setup zu starten kann ja wohl nicht so> schwer sein.
Man sollte schon alles lesen:
Gerhard Z. schrieb:> Die Entwicklungsumgebung habe ich in der virtuellen Windos-Installation.> Dort stürzt das Programm aber nicht ab.
Gerhard Z. schrieb:> Karl Heinz schrieb:>> Abspecken. Zerlegen in Einzelmodule und einzeln rigoros testen.>> Ja, ich glaube, da muss ich durch. Habe an mehreren Stellen malloc im> Program um Platz zu scghaffen, um Binärdateien 1:1 in den Speicher> einzulesen. Habe jetzt mal einfach den doppelten Platz reserviert.> Programm stürzt zwar auch ab, aber jetzt sind die Ergebnisse> geschrieben. Wenn ich aber z.B. den 4-fachen Platz reserviere, dann> stürzt es wieder ab und alle Dateien haben 0 Byte.
Ja.
Aber blindes Rumprobieren hilft hier nicht weiter.
> Alles in Richtung Visual Studio oder ähnliches ist lieb gemeint, hilt> mir aber im Moment nichts. Müsste erst ein eigenes Windows System> aufsetzen und entsprechende Toolchains installieren. Da scheu ich ein> bisschen vor zurück.
Ist eine Sache auf 10 Minuten, in denen die Kiste ganz alleine werkelt.
Man kann MS viel vorwerfen, aber die Installation vom Dev-Studio läuft
problemlos durch. Am Anfang die 'üblichen Verdächtigen' einstellen und
der Rest geht von alleine.
Peter II schrieb:> Aber man hat den Vorteil das ein andere Compiler eventuell> das Problem anders darstellt und man so auf die Lösung kommt.Das ist sowieso immer gut.
Jeder Compiler wirft andere Warnungen. Je mehr Compiler drüber gejagt
werden, desto mehr dubiose Stellen findet man meistens.
valgrind ist gut.
Die MS-Runtime kann auch weiterhelfen.
Die Debug Build Versionen von malloc und free machen zusätzlichen
Speichercheck.
https://msdn.microsoft.com/en-us/library/2f7sy2e9.aspx?f=255&MSPPError=-2147217396
Technisch ist das so gelöst, dass malloc etwas mehr Speicher reserviert
als angefordert und in diesen Überschussspeicher ein bestimmtes Muster
reinschreibt. Bei einem free (bzw beim Aufruf von bestimmten Funktionen)
werden diese Speicherbereiche abgesucht, ob das Muster immer noch
drinnen steht. Wenn nicht, dann hat in der Zwischenzeit irgendein Code
den Speicher überschrieben, obwohl er nicht sollte.
utf8 versus utf16 glaub ich nicht.
Das Projekt besteht darin eine WAV Datei einzulesen, durch Filter zu
jagen und die gefilterten Ergebnisse auf neue Dateien auszugeben.
Da ist nicht viel String Verarbeitung im Spiel.
Ich schätze mal, dass irgendeiner der Filter schlampig gemacht ist, und
seine Ausgabespeicherfläche überläuft. Aber das ist nur eine erste
Schätzung basierend auf den üblichen und häufigen Fehlermustern.
Blöd ist natürlich, dass der TO keinen Code zeigen kann. So umfangreich,
denke ich mal, kann diese Aufgabenstellung nicht sein, dass man da nicht
mit formalen Kriterien einfach mal den Code durchackert und an allen
dubiosen Stellen mal ein paar assert reinwirft.
Karl Heinz schrieb:> Technisch ist das so gelöst, dass malloc etwas mehr Speicher reserviert> als angefordert und in diesen Überschussspeicher ein bestimmtes Muster> reinschreibt. Bei einem free (bzw beim Aufruf von bestimmten Funktionen)> werden diese Speicherbereiche abgesucht, ob das Muster immer noch> drinnen steht. Wenn nicht, dann hat in der Zwischenzeit irgendein Code> den Speicher überschrieben, obwohl er nicht sollte.
Das ist schön und gut, aber der TO gibt seinen Speicher ja nicht frei
weil das das Betriebssystem für ihn tut:
Gerhard Z. schrieb:>> Hat denn jedes Mallc sein free?> Nein, es gibt kein free; der Speicher wird bis zum Programmende benutzt> und ich bin davon ausgegangen, dass das Betriebssystem beim Terminieren> des Programms den Speicher freigibt. Ist da mein Denkfehler?
Das ist zwar richtig aber ganz schlechter Stil. Man sollte sich
angewöhnen sowas sauber zu machen. Aus dem main() wird vieleicht auch
mal eine normale Funktion, die von einem anderen Programm gerufen werden
kann.
Nichtinitialisierte Pointervariable ist ein heisser Kandidat, das
erklärt auch unterschiedliches Verhalten auf unterschiedlichen Systemen
bzw. VMs.
Rolf Magnus schrieb:> Man sollte schon alles lesen:>> Gerhard Z. schrieb:>> Die Entwicklungsumgebung habe ich in der virtuellen Windos-Installation.>> Dort stürzt das Programm aber nicht ab.
richtig, darum habe ich auch schon oben geschrieben, das es dann eine
remote Debugger gibt, den man nicht installieren muss.
Udo Schmitt schrieb:> Karl Heinz schrieb:>> Technisch ist das so gelöst, dass malloc etwas mehr Speicher reserviert>> als angefordert und in diesen Überschussspeicher ein bestimmtes Muster>> reinschreibt. Bei einem free (bzw beim Aufruf von bestimmten Funktionen)>> werden diese Speicherbereiche abgesucht, ob das Muster immer noch>> drinnen steht. Wenn nicht, dann hat in der Zwischenzeit irgendein Code>> den Speicher überschrieben, obwohl er nicht sollte.>> Das ist schön und gut, aber der TO gibt seinen Speicher ja nicht frei> weil das das Betriebssystem für ihn tut:
Da gibt es auch eine Funktion, mit der man den Checker zwischendurch
anwerfen kann.
Das Programm in Abschnitte aufteilen, nach jedem Abschnitt prüfen lassen
und man hat zumindest schon mal eine grobe Vorstellung davon bis wohin
zumindest an dieser Front noch nichts Auffälliges vorgefallen ist.
Dependency Walker, depends.exe, Microsoft
Debugging Tools for Windows aus dem SDK (Eruierung, Analyse)
Beide Tools kosten nichts und funktionieren sehr gut.
Eventuell auch mal mit Clang/LLVM kompilieren. Kost ebenfalls nichts und
zwei Compiler sehen mehr als einer.
Wenn man ein Tool zur statischen Codeanalyse hat, sollte man dieses
natürlich mal über den Code laufen lassen. Die Tools die was taugen
kosten aber nicht selten auch (deutlich) was.
Peter II schrieb:> murkser schrieb:>> Dependency Walker, depends.exe, Microsoft>> Wie hilft diese denn bei den Problem weiter?>> Jetzt zu meiner Frage: Wie kann ich am besten unter Windows den Fehler>> einkreisen.
Dependency Walker, depends.exe, Microsoft
zeigt u.a. Abhängigkeiten ...
Debugging Tools for Windows aus dem SDK (Eruierung, Analyse)
Monitor in Echtzeit mit detailliertem Protokoll
Ansonsten noch prüfen:
1.) Werden alle Variablen und Arrays zu Beginn des Programms richtig
initialisiert?
2.) Werden sie auch während der Laufzeit nochmal neu initialisiert, wenn
dies erforderlich ist?
2.) Werden alle Zeiger richtig initialisiert?
3.) Werden alle Zeiger ernsthaft richtig initialisiert?
4.) Werden alle Zeiger jetzt wirklich ernsthaft richtig und dreifach
überprüft korrekt initialisiert? :-)
90% aller Abstürze in C-Programmen rühren von Zugriffen auf Zeigern her,
die auf etwas Ungültiges verweisen. So pflegte es unser Informatik-Prof
zu sagen. Der Mann hatte in 90% aller Fälle Recht. ;-)
Ach ja! Alle Compiler-Warnungen müssen untersucht und in der Regel auch
behoben werden. Guter Code zeichnet sich unter anderem dadurch aus, dass
er ohne jede Warnung kompiliert.
So, sorry, dass ich so lang nicht geantwortet habe, war sehr
beschäftigt.
Habe jetzt mal valgrind angeschmissen und hätte gerne Hilfe. Ich
versuche die Fehler aufzuarbeiten in der Reihenfolge, in der sie
valgrind rausschreibt. Zunächst ist offensichtlich etwas in meinem
Antialiasing Tiefpass zu bemäkeln (muss die Wavedaten von 48000 auf 3250
Hz runtersamplen). Zunächst mal der Code des Filters:
Die filter.h Datei:
f=LPF24dB_init(48000,800/* corner frequency */,1.0/* passband ripple */);
und später:
1
doubleRvalue;
2
Rvalue=irgendwas;
3
Rvalue=LPF24dB(f,Rvalue);
valgrind schmeißt mir als erstes folgenden Fehler raus:
==2429== Invalid write of size 8
==2429== at 0x804E11E: LPF24dB_init (filter.c:30)
==2429== by 0x8049F61: EngineNextSampleFromFile (fake_ecu.c:246)
==2429== by 0x804B502: DA_Exhaust_AD (fake_ecu.c:619)
==2429== by 0x804BB51: main (ednc_sim.c:161)
Wobei folgendes die Zeile 30 ist:
Gerhard Z. schrieb:> typedef struct> {> double A[6];> double B[6];> double State[4];> } FILTERSTATE_t;> ...> FILTERSTATE_t *f;> ...> f=malloc(sizeof(f));> if (f==NULL) return(f);
Was liefert sizeof(f) zurück? Die Länge des Structs oder die Länge eines
Zeigers auf einen Struct?
Final:
Das war's, jetzt läuft es in Windows auch anstandslos! Ich danke euch
noch mal für eure Hilfen. Wir können den Faden schließen.
Etwas erstaunlich ist - valgrind zeigt mir jetzt keinen Fehler mehr in
meinem Code, aber offensichtlich in libc-start.c?!
==3609== Conditional jump or move depends on uninitialised value(s)
==3609== at 0x4079D77: log10f (w_log10f.c:28)
==3609== by 0x40BA934: (below main) (libc-start.c:260)
==3609==
==3609== Conditional jump or move depends on uninitialised value(s)
==3609== at 0x40EAF1D: __printf_fp (printf_fp.c:404)
==3609== by 0x40E638C: vfprintf (vfprintf.c:1654)
==3609== by 0x40EF7DE: fprintf (fprintf.c:32)
==3609== by 0x40BA934: (below main) (libc-start.c:260)
==3609==
usw.
Oder ist das was, was ich noch irgendwo verbockt habe?
Gerhard
valgrind --track-origins=yes
http://valgrind.org/docs/manual/mc-manual.html
"Controls whether Memcheck tracks the origin of uninitialised values. By
default, it does not, which means that although it can tell you that an
uninitialised value is being used in a dangerous way, it cannot tell you
where the uninitialised value came from."
Hier hat man nahezu alles richtig gemacht, was die Benennung der
Variablen bzw. der Funktion betrifft.
Und dann sowas:
1
doubleK,sg,cg;
2
FILTERSTATE_t*f;
3
4
f->B[0]=f->A[0]*K;
5
f->B[1]=2*f->B[0];
6
f->B[2]=f->B[0];
7
8
f->B[3]=f->A[3]*K;
9
f->B[4]=2*f->B[3];
10
f->B[5]=f->B[3];
Das ist Code von der Sorte, den später keiner vernünftig warten kann.
Warum hat alle Welt solche Angst vor selbst sprechenden Bezeichnern und
vor vernünftig eingesetzten Kommentaren?
Früher gab es die Argumente:
-Speicherplatz (für den Sourcecode und für Kommentare) ist knapp, also
verwendet man so wenige Buchstaben wie möglich für die Bezeichner und
spart sich Kommentare am besten gleich ganz
-Mit kürzeren Namen für Funktionen und Variablen spart man sich
Tipparbeit
Heutzutage gelten beide Argumente schon sehr lange nicht mehr.
Speicherplatz ist in Hülle und Fülle vorhanden. Jeder moderne Texteditor
beherrscht Auto-Vervollständigung aus dem Effeff. Es gibt keinen
vernünftigen Grund mehr, Bezeichner wie "f" oder "a" oder so etwas in
der Art zu verwenden. Einzige legale Ausnahme: Die typischen
Indexvariablen wie i und j bei Schleifen.
C bietet einem 31 Buchstaben pro Bezeichner, also nutze man sie verdammt
noch mal! ;-)
Der Kommentar hier ist nutzlos, ja sogar irreführend:
1
K*=K;// (just to optimize it a little bit)
Später weiß kein Mensch mehr, warum um alles in der Welt das Quadrieren
eines Wertes "eine kleine Optimierung" darstellen soll. Das ist aber
gerade der Sinn eines Kommentars: Zu erläutern, warum man etwas so
macht wie man es macht.
Ein möglicher Test für Code-Qualität ist:
Man lese seinen eigenen Code ein Jahr, nachdem man ihn geschrieben hat.
Kann man sofort und intuitiv verstehen, was man da verzapft hat? :-)
Nebenbei bemerkt bräuchte man kein malloc (und kein LPF24dB_free), wenn
der Aufrufer der Funktion LPF24dB_init einen Zeiger auf ein
FILTERSTATE_t mitgeben würde.
hauspapa schrieb:>> if (f==NULL) return(f);>> Kurze Rückfrage von einem Programmieranfänger:> if Anweisung ohne {} geht sowas?
Ja es geht, ist aber nicht empfohlen laut z.B. MISRA-Richtlinien.
hauspapa schrieb:> if Anweisung ohne {} geht sowas?
ja, die {} braucht man nur um mehre Anweisungen zu schreiben. Aber ist
es empfohlen immer die {} zu verwenden.
hauspapa schrieb:>> if (f==NULL) return(f);>> Kurze Rückfrage von einem Programmieranfänger:> if Anweisung ohne {} geht sowas?
hatte mir das in Pascal angewöhnt, weil dort mir ein begin ... end;
(anstatt { ... } in C) für eine Anweisung als Overkill vorkam. Aber
natürlich gibt es eine gewisse Gefahr mit der Schreibweise. Daher halte
ich die Anweisung bei Nichtklammerung nach Möglichkeit immer in der
gleichen Zeile, um nicht durch z.B. Einrückung in der nächsten Zeile
vorzutäuschen, man könnte einfach weitere Zeilen dem if zuordnen. (Geht
nur leider nicht, wenn man die if clause debuggen will).
An die Anderen: Weiterhin Danke für eure Tips zum Programierstiel. Werde
sie versuchen, weitgehend einzuarbeiten.
Gerhard
Mark Brandis schrieb:> Es gibt keinen vernünftigen Grund mehr, Bezeichner wie "f" oder "a" oder so> etwas in der Art zu verwenden.
Doch, es gibt einen: Man bildet eine mathematische Funktion nach, bei
der die Namen auch so sind. Vergleiche auch x und y für Koordinaten.
Sollte man die etwa KoordinateInHorizontalerRichtung und derlei nennen,
nur damit sich nicht nur ein Zeichen lang sind?
> Man lese seinen eigenen Code ein Jahr, nachdem man ihn geschrieben hat.> Wenn man ihn nicht sofort und intuitiv verstehen kann, dann hat man> nicht gut programmiert.
Toll. Dann weiß ich, daß ich vor einem Jahr schlechten Code geschrieben
habe. Hätte ich das mal vor einem Jahr gewusst...
> Es gibt keinen vernünftigen Grund mehr, Bezeichner wie "f" oder "a" oder> so etwas in der Art zu verwenden.
So pauschal ist das doch völliger Unfug von Gutmenschenprogrammieren,
die am Abend nur dann beruhigt einschlafen können, wenn sie ein goto
durch 10 ifs und try-catch'es ersetzen konnten.
Rolf Magnus schrieb:> Toll. Dann weiß ich, daß ich vor einem Jahr schlechten Code geschrieben> habe. Hätte ich das mal vor einem Jahr gewusst...
Ein richtig guter Programmierer zu werden dauert mindestens mehrere
Jahre, wenn nicht gar ein Jahrzehnt oder noch länger. Wer etwas anderes
behauptet, der lügt. ;-)
Georg A. schrieb:> ... ist ja auch soooo vieeeel besser zu lesen.
Ich find's besser zu lesen. Entweder so, oder aber man schreibt direkt
zu der Funktion einen Kommentar hinzu, der die Bezeichner erläutert:
1
/*
2
f: Filterstatus
3
A: Filterkoeffizient A
4
B: Filterkoeffizient B
5
K: Konstante Verstaerkung
6
*/
Und goto ist ganz arg böse! Ja. Da stirbt jedesmal ein kleines
Hundebaby, wenn man es benutzt.
Zugegeben gibt es viel wildere und unverständlichere Beispiele als das
hier mit dem digitalen Filter. Wenn ich einen Euro hätte für jedes Mal,
bei dem ein Programmierer unverständliche Bezeichner verwendet hat, dann
bräuchte ich nicht mehr arbeiten gehen.
Mark Brandis schrieb:> Ich find's besser zu lesen. Entweder so, oder aber man schreibt direkt> zu der Funktion einen Kommentar hinzu, der die Bezeichner erläutert:
Ja und nein...
Das Problem ist, dass gerade im Mathe/Physikbereich mehr oder weniger
alles nur einen Buchstaben hat, wenn auch stellenweise mit Dach,
Schlange, Unterstrich, Überstrich, lateinische/griechische/irgendwas
Großbuchstaben/Kleinbuchstaben/Symbole und das je nach Kontext/Fach ein
und dasselbe Symbol was anderes bedeuten kann.
Aber...
1. Will zumindest ich so was möglichst 1:1 übernehmen, damit es leichter
mit dem Original vergleichbar ist
2. Habe ich es lieber wenn ich die gesamte Formel auf einmal sehen kann
ohne zu scrollen/Augen/Kopf unnötig bewegen zu müssen (ebenso bei
Methoden/Funktionen, gut das es noch Monitore mit Pivot-Funktion bzw. im
Nicht-Konsumentenformat gibt).
> Und goto ist ganz arg böse! Ja. Da stirbt jedesmal ein kleines> Hundebaby, wenn man es benutzt.
Oder um in dem Bild zu bleiben: Verhungert im Klammerndschungel der
vielen, vielen u.U. nötigen Ifs, whiles etc.
Also so lange Namen, die sich dann aber nur in einem Zeichen, und dann
auch noch erst dem letzten, unterscheiden, finde ich persönlich schwerer
zu lesen, da schlechter unterscheidbar. Da muß ich viel länger drauf
schauen, um an jeder Stelle zu erkennen, ob jetzt A oder B gemeint ist.
Arc Net schrieb:> gut das es noch Monitore mit Pivot-Funktion bzw. im Nicht-Konsumentenformat> gibt).
Ich habe letztens festgestellt, daß es einen Monitor in 1:1 gibt, mit
1920x1920 Pixeln Auflösung.
Mark Brandis schrieb:> Ein richtig guter Programmierer zu werden dauert mindestens mehrere> Jahre, wenn nicht gar ein Jahrzehnt oder noch länger.
Das ist mir bewußt, denn ich bin schon eine ganze Weile bei "oder noch
länger". Man kann aber auch nur dann ein "richtig guter Programmierer"
werden, wenn man sich von so leeren Floskeln wie:
Mark Brandis schrieb:> Und goto ist ganz arg böse!
trennt und Dinge selbst hinterfragt.
Rolf Magnus schrieb:> Ich habe letztens festgestellt, daß es einen Monitor in 1:1 gibt, mit> 1920x1920 Pixeln Auflösung.
Es geht doch :-)
Schade, dass er durch den Preis ein Nischenprodunkt bleibt.
Und der Trend geht ja zu 4K.
Rufus Τ. Firefly schrieb:> Ja. *Endlich!*. Allerdings ist die Preisvorstellung, die die wenigen> Onlinehändler, die ihn verkaufen, noch jenseits von gut und böse:
So wenige sind das doch eigentlich nicht. Der Preis wird sich vermutlich
zusammensetzen aus der Tatsache, daß der Monitor von Eizo ist (die schon
immer teuer waren) und daraus, daß die Stückzahlen vermutlich eher
gering sind.
Rolf Magnus schrieb:> Der Preis wird sich vermutlich zusammensetzen aus der Tatsache, daß der> Monitor von Eizo ist (die schon immer teuer waren) und daraus, daß die> Stückzahlen vermutlich eher gering sind.
Der Monitor ist neu und erst seit Januar überhaupt auf dem Markt.
Da --abgesehen von einer Produktankündigung im Dezember-- nirgends etwas
über diesen Monitor verlautbart wurde, es von Eizo auch keine Reklame
dafür gibt (bzw. zu geben scheint), ist die Marktdurchdringung auch eher
überschaubar.
Reduziert man die Händler, die den Monitor gelistet haben, auf die Menge
der Händler, die den Monitor tatsächlich vorrätig haben, wird die Liste
auch deutlich übersichtlicher -- das sind dann nämlich nur noch vier.
Rolf Magnus schrieb:> Das ist mir bewußt, denn ich bin schon eine ganze Weile bei "oder noch> länger". Man kann aber auch nur dann ein "richtig guter Programmierer"> werden, wenn man sich von so leeren Floskeln wie:>> Mark Brandis schrieb:>> Und goto ist ganz arg böse!>> trennt und Dinge selbst hinterfragt.
Zeig mir bitte ein Beispiel, in dem ein goto die beste mögliche Lösung
darstellt. Ich bin gespannt :-)
Mark Brandis schrieb:> Zeig mir bitte ein Beispiel, in dem ein goto die beste mögliche Lösung> darstellt. Ich bin gespannt :-)
Rausspringen aus verschachtelten Schleifen (aus Performancegründen).
Andreas schrieb:> Mark Brandis schrieb:>> Zeig mir bitte ein Beispiel, in dem ein goto die beste mögliche Lösung>> darstellt. Ich bin gespannt :-)>> Rausspringen aus verschachtelten Schleifen (aus Performancegründen).
Hierzu darf ich stackoverflow.com zitieren:
"Nesting lots of loops is usually a code smell all it's own. Unless you
are doing, like, 5-dimensional array multiplication, it's hard to
picture a situation where some of the inner loops couldn't be usefully
extracted into smaller functions. Like all rules of thumb, there are a
handful of exceptions I suppose."
Quelle:
http://stackoverflow.com/questions/46586/goto-still-considered-harmful#comment959380_47472
Mark Brandis schrieb:> Andreas schrieb:>> Mark Brandis schrieb:>>> Zeig mir bitte ein Beispiel, in dem ein goto die beste mögliche Lösung>>> darstellt. Ich bin gespannt :-)>>>> Rausspringen aus verschachtelten Schleifen (aus Performancegründen).>> Hierzu darf ich stackoverflow.com zitieren:>> "Nesting lots of loops is usually a code smell all it's own. Unless you> are doing, like, 5-dimensional array multiplication, it's hard to> picture a situation where some of the inner loops couldn't be usefully> extracted into smaller functions. Like all rules of thumb, there are a> handful of exceptions I suppose.">> Quelle:> http://stackoverflow.com/questions/46586/goto-still-considered-harmful#comment959380_47472https://www.kernel.org/doc/Documentation/CodingStyle
The rationale for using gotos is:
- unconditional statements are easier to understand and follow
- nesting is reduced
- errors by not updating individual exit points when making
modifications are prevented
(der letzte dort noch aufgeführte Punkt ist hier absichtlich nicht mit
aufgeführt)