Aufgabe 6: Quellcodelokalisierung und Quellcodeanalyse
Christian Becker, Michael Bell, Matthias Füssel, Sven Heine, Uwe Knaur
Die Abarbeitung der Aufgabenstellung erfolgte anhand der beiden vorgeschlagenen
Traceläufe. wir haben zu jeder Funktion versucht, kurz die entscheidenden Merkmale
herauszugreifen ohne nochmehr Papier als ohnehin schon nötig zu produzieren
- damit das ganze noch benutzbar bleibt. Ein zu langes Dokument wird schließlich
niemand benutzen wollen, wenn er kurz wissen will, was eine Funktion macht.
Hier folgt nun die Auswertung der Funktionen, die bei dem ersten Tracelauf aufgefallen
sind.
- Konstruktor vom Justagedialog (lt. Kommentar)
- setzt Defaultwerte
- Riesenkommentarzeilen vorher - ohne Inhalt
- setzt Defaultwerte
- lädt Standard Makro Befehle (lt. Kommentar)
- scheint zu stimmen
- keine Rückkehrcodes definiert - nur true oder false, aber wenigstens das sauber
- benutzt mehrfach die Funktion TSteering::LoadMacro zum Laden von Makros
- kleiner Tip - man schreibt Visualizing mit z
- setzt einige Werte, die sich auf spätere Reportausgaben beziehen (lt. Kommentar)
- wenn die ganzen b_id_* nicht wirklich benutzt werden, warum sind sie dann
definiert und das auch noch global ?!
- setzt das Bezugsfenster, aktiviert Motorachse mid, setzt Zaehler auf sensid
(lt. Kommentar)
- Rückkehrwert ist sinnlos, da garkeine Tests laufen
- lädt Macros, wird mehrfach von TSteering::Initialize genutzt
- lädt die Macros aus Datei
- bei Fehler wird ein Fenster per MessageBox () aufgetan
- zum Parsen des Files werden folgende Funktionen benutzt
- GetFileLine
- ParsingMacroId
- MessageBox, falls was schiefgegangen ist
- ParsingCmd
- beim Parsen wird eine Fehlerstabilisierung lt. Kommentar versucht, ob diese
korrekt ist steht auf einem anderen Blatt
- MessageBox wird als Parameter immer getFocus mitgegeben
- etwas wenig Kommentare
- der Name sagt alles
- keine Kommentare
- setzt Macronamen im übergebenen TMacroTag
- prüft die MacroID gegen den Array aMacroList
- gibt true oder false zurück, wobei false bei einem Duplikat oder nicht möglicher
Identifizierung ist
- die Rückkehrcodes sind wieder nicht eineindeutig
- SetInfo wird im Fehlerfalle benutzt
- keine Kommentare
- keine Kommentare
- while-Schleife testet auf verschiedene Kommandos und setzt die entsprechende
cmd.id und cmd.P1 (ParsingCmdParam wird genutzt)
- bei SetupAreaScan wird die Funktion ParsingXScanType für das Parsen des Parameters
genutzt
- AreaScan, Scan evtl. das gleiche wie bei SetupAreaScan
- ChooseAxis - mlParsingAxis für Parameterparsen
- ChooseDevice - dlParsingDevice für Parameterparsen
- warum hier ein while(1)-loop eingesetzt wird ist mir nicht klar, das sowieso
im ersten Durchlauf garantiert ein break kommt
- es folgt eine saubere Fehlerkontrolle und die Ausgabe mit MessageBox
- die Rückkehrwerte sind true und false (wegen der sauberen Fehlermeldungen ist
dieses Verhalten aber in Ordnung)
- keine Kommentare
- nur strcmp-Vergleiche auf Keywords
- die versuchte Beschleunigung per Größer- und Kleinerzeichen ist ja wohl das
Letzte, auch wenn man nur für Win32 also ASCII programmiert und EBDIC (IBM S390)
keine Rolle spielt
Was zuerst auffällt sind die Kommentare. Solange sie trivial sind, sind sie
schön sauber und teilweise riesengroß vorhanden, soll heißen völlig unverhältnismäßig
zur Bedeutung. In dem Moment, wo es nicht mehr nur um Defaultwerte oder triviale
selbsterklärende Funktionsrufe geht, fehlen sie fast vollständig.
Der nächste augenscheinliche Fall von Inkonsistenz tritt bei den Rückmeldungen
auf. Wieso wird einmal MessageBox benutzt und ein anderes mal SetInfo? Desweiteren
fällt auf, daß die MessageBox immer getFocus () als Argument bekommt. Wenn dies
immer geschieht und nicht objektgebunden ist, so kann das die MessageBox auch
selber tun und belastet damit nicht das Interface. Da es sich wahrscheinlich
um eine Toolkitfunktionalität handelt, ist die Frage, ob es sich bei der häufigen
Anwendung lohnt einfach eine Wrapperfunktion zu schreiben (ich denke mal nicht).
Extrem aufgefallen ist der unschöne Hack in TSteering::ParsingCmdParam, um die
strcmp-Anfragen zu beschleunigen. Soetwas ist extrem gefährlich weil fehleranfällig.
Weiterhin unter die Kategorie unschön fällt die Einschubweise. Mal sind es Tabulatoren
ein anderes Mal zwei Leerzeichen.
Im Sinne von OO ist es nicht akzeptabel, so viele globale Variablen zu haben.
Außerdem ist es nicht besonders toll, um es mal vorsichtig zu formulieren, direkt
über die Definition von globalen Variablen auch noch zu Schreiben, daß man sie
eigentlich garnicht braucht und dann solche Variablen auch noch als temnporäre
Variablen benutzt. Soetwas kann eigentlich nur irgendwann ins Auge gehen.
- was das für ein Konstruktor ist, muß ja wohl nicht kommentiert werden
- folgende Funktionsaufrufe kommen von diesem Konstruktor (können also aussortiert
werden aus den Tracefiles ;-D)
- GetPrivateProfileInt
- Current
- Voltage
- Autocalibration
- Correction (of ManualMoves)
- GetPrivateProfileString (kein Rückkehrwert?)
- User
- Target
- Substrat
- Wavelength
- Reflection
- Orientation
- Comment
- StartUp
- Environment
- GetWindowsDirectory (kein Rückkehrwert?)
- CreateMenu
- SetHKL(kein Rückkehrwert?)
- welche Defaultwerte die Parameter bekommen bei der Initialisierung, kann man
im Code nachschauen und meiner Meinung nach hier nichts verloren, da das Verständnis
dadurch keineswegs gefördert wird
- warum heißen hier Funktionen GetXYZ obwohl sie gar kein richtiges Get durchführen?
(Achtung nicht polemisch sehen, ich bin kein Windowsprogrammierer und kenne
daher keine Systemrufe an die Win32-API.)
- es gibt extent und extension im Englischen aber kein extention (also massenweise
falsche Namen - wenn's schon Englisch sein muß, dann bitte doch etwas korrekter)
- was bedeutet int PASCAL in der Funktionsdeklaration ???
- mir ist gerade aufgefallen, daß hier ab und zu Tabulatoren zum Einrücken verwendet
wurden (Dies ist extrem Editor abhängig und sollte nicht benutzt werden. Die
meisten Editoren lassen sich von Tab auf zwei Leerzeichen oder so umkonfigurieren.)
- GetClassInfo ignoriert anscheinend einen Rückkehrcode (ein Variante mit demselben
wurde auskommentiert)
- evtl. C-Macros (alles in Großbuchstaben bedeutet in C normalerweise Macro):
- MAKEINTRESOURCE
- COLOR_APPWORKSPACE
- FORWARD_WM_COMMAND
- check auf Konfigurationsdatei
- Konfiguration falls vorherige Instanz nicht verfügbar
- Durcharbeiten der MessageQueue (while (!SetMessageQueue (cnt-)))
- Accelerator laden
- Messages absetzen und Fenster initialisieren
- Timer testen und gegebenenfalls Fehlermeldung machen
- Parameter setzen per SetParameters (lt. Kommentar bedeutet das Hardwareinitialisierung)
- MessageLoop anstoßen (ist wohl der eigentliche Arbeitsschritt)
- folgende Rufe treten nach dem Start von WinMain auf:
- LoadAccelerators
- GetClassInfo
- RegisterClass
- SetMessageQueue
- LoadAccelerators
- RegisterWindowMessage
- ShowWindow
- UpdateWindow
- SetTimer
- CreateWindow
- KillTimer
- MessageBox mit GetFocus
- SetParameters
- nach SetParameters wird es interessant, dort startet nämlich per MessageLoop
die eigentliche Arbeit der Klasse
- die Rückkehrcodes scheinen sauber implementiert worden zu sein (null und vier)
- Kommentare sind wieder mal Fehlanzeige außer bei SetParameters - das war dann
wohl wieder trivial genug
- CLIENTCREATESTRUCT ist eine Struktur und keine Variable. Wenn dies für alle
großgeschriebenen Namen gilt, dann wahrscheinlich auch für die WinMain vorkommenden.
Dies ist absolut atypisch, da diese Schreibweise normalerweise Macros signalisiert.
- die Funktion erzeugt ein neues MDI-Client Window
- was ist das?
- Benamung von Funktionen inkonsistent - es tritt auch ...MDI... auf
- saubere Returncodes
- endlich mal gute hilfreiche Kommentare
- verschiebt Window auf obere linke Ecke und paßt die Größe an
- keine Kommentare
- malt Bild aus Struktur heraus - Ausnahme Shutdown
- während des Malens werden BlastStatusLine und SetWatchIndicator laufen gelassen
- zeichnet Status - Ausnahme Shutdown (warum wird das hier nochmal gefangen, wo
es doch schon von DoPaint abgefangen wird (Probleme mit der Interfacespezifizierng?)
- Anzeige der Statusinformationen - Ausnahme Shutdown
- autsch, was sind denn das für if-Strukturen
- setzt Status via BlastStatusLine nach kurzer Aufbereitung - Ausnahme wieder
Shutdown
Diese Funktion macht nichts anderes, als aus den globalen Parametern die Struktur
Parameters zu bestücken. Es ist auch wieder nix gewesen mit der Objektorientierung.
Es gibt keine Kommentare - dies ist hier auch nicht nötig.
In dieser Funktion werden die Kommandos ausgeführt bzw. überhaupt erst erkannt
(sprich interpretiert).
- falls Initialsierung
- prüfen der DLLs
- motors.dll
- counters.dll
- device32.dll
- LoadMenuBar
- TSteering::Initialize unter Nutzung von Device per GetCounterListPtr()->GetDevice
- TTopography::Initialize
- wenn Main::bAutoCalibration dann noch schnell per Dialog die Werte einsammeln
- Fenster vorbereiten
- SetInfo vom Startup (der Vorbereitung der Fenster)
- abarbeiten aller anderen Kommandos
- In dieser Funktion wird auf SetInfo gesetzt. Nur am Schluß ist es mal SendMessage
(evtl. für MessageLoop?).
- lädt Fenstermaße via GetPrivateProfileInt und positioniert abschließend das
Fenster
Hierbei handelt es sich um eine absolut Kernfunktion der Klasse TMain. Sie wird
durch TMain::WinMain ``angeworfen''.
- while (GetMessage(...))
- if not TranslateMDISysAccel and notTranslateAccelerator
- TranslateMessage
- DispatchMessage
- return 0
Zuerst einmal sind die Rückkehrcodes sinnlos, da es nur null gibt und dann fehlen
sämtliche Kommentare. Der Stil mit den Tabulatoren läßt sich eigentlich nur
in einem Editor ertragen, der dies automatisch konvertiert. Der auskommentierte
Code deutet auf Bastelei hin und fördert nicht gerade das Vertrauen gerade bei
der mangelhaften Auskommentierung. Da die Funktionen nicht im Code zu finden
sind und auch nicht protokolliert wurden, wurden diese Codeteile auch nicht
erreicht, was logisch erscheint, da nichts getan wurde, sind anscheinend auch
keine Messages generiert worden. Das Messagehandling ist aber wohl woanders
implementiert - evtl. handelt es sich sogar um Win32-API-calls, aber mit den
Kenntnissen des Autors in Win32 ist dies nicht zu klären.
MenuSelect kümmert sich um die Auswahl in den Menüs. Die eventuell auftretenen
Nachrichten werden via PostMessage übermittelt.
Die Funktion sichert sämtliche Werte, die vom Konstruktor wieder geladen werden.
Es wird ausschließlich WritePrivateProfileString benutzt nicht aber WritePrivateProfileInt
(wieder eine Inkonsistenz?).
Hier gelten die gleichen Kommentare wie für m_steer.cpp. Dazu kommt noch die
Entdeckung, daß es Funktionen und Variablen anscheinend gibt, die komplett groß
geschrieben wurden. Diese Schreibweise ist gerade in C mit seinem Präprozessor
den Macros vorbehalten. Auch wenn etwas wichtig ist, sollte man nicht diese
Schreibweise nutzen. Teilweise sind aber schon einige wesentliche Kommentare
da, ist nur die Frage von wem sie sind ;-) Eine böser Stilfehler steckt noch
in SetWatchIndicator. Die Kaskade von if-Anweisungen muß ja wohl nicht sein.
Ein inhaltliches Problem stellen die gesamten Statusfunktionen dar, die sämtlichst
immer auf einen möglichen Shutdown testen. Hier sollte man eine zentral Prüfstelle
festlegen oder genau definieren welche Funktionen darauf testen. Es muß nicht
sein das jede dieser Funktionen darauf testet, dann die nächste Funktion ruft
und die das nochmal tut.
Die hier angegebenen Klassen sollen ignoriert werden, was wir hiermit tuen.
Hier werden einige hardgecodete Initialisierungen vorgenommen.
Es werden mittels GetPrivateProfileString mehrere Variablen aus dem ini-File
gelesen
- WorkPoint
- ControlRange
- ControlStep
- ExposureTime
- ExposureCounts
Es wird wieder nicht GetPrivateProfileInt benutzt.
Also als erstes mal was zum Englischen. Wenn man in einem rein lokal begrenzten
Umfeld schon alles ins Englische transformieren will, so soll man doch bitte
nicht soviele offensichtliche Fehler einbauen. Allerdings muß ich einräumen,
daß ich in einem internationalen Projekt letzens diverse Optionen und Variablen
ModulXYZ genannt habe und dies erst in der zweiten Version korrigiert habe.
Mit den Kommentaren ist das so eine Sache - bei Trivialitäten sind sie kein
Problem aber da und wenn es ernst wird hat man schon verloren, wenn einem auffällt
das Ernst wird. Gerade die Algorithmen zur Erfassung von Macros etc. müssen
dokumentiert sein, um ihre Korrektheit prüfen zu können, da sie ja sogar Fehlerstabilisierung
versuchen. Hier sollte man vielleicht ansetzen, um später schnell Konfigurationsfehler
von Programmfehlern unterscheiden zu können.
Ein weiteres Problem ist der Stil der Einrückungen, was aber relativ einfach
behebbar sein sollte. Ein viel größeres Problem ist, daß anscheinend keine genaue
Interfacedefinition durchgeführt wurde, was dazu führte, das einige Tests doppelt
oder noch öfter durchgeführt wurden.
Problematisch bei der Bewertung stellte sich heraus, daß einige Mitglieder der
Gruppe so vor allem auch der Schreiber keine Ahnung von der Win32-API haben.
Hier liste ich nur noch die Besonderheiten auf, d.h. alle Funktionen, die beim
ersten Durchlauf nicht erkannt wurden. Da wir TModalDlg ignorieren sollen bleiben
nur noch die zwei Funktionen von m_dlg.cpp übrig. Eine Zusammenfassung spare
ich mir deshalb mal.
Der Name der Funktion paßt nicht in das übliche Schema des Codes. Die Funktion
wird eigentlich nur zur Datenübergabe an ein Objekt von der Klasse TModalDlg
benutzt.
Diese Funktion prüft, ob die Einstellungen im Dialog möglich sind. Dabei wird
das Deviceobhect testhalber konfiguriert. Es handelt sich insgesamt um zwei
checkbuttons und drei Integerwerte. Eine Dokumentation wäre dringend angebracht,
da hier inhaltliche Fehler passieren könnten. Der Code an sich ist klar, da
er einfach ist ;-)
An dieser Stelle möchte ich nur noch einmal kurz die wichtigsten Sachen zusammenfassen
und nicht nochmal breittreten.
- die Kommentare fehlen immer dort, wo es kompliziert wird
- die Formatierung des Codes läßt zu wünschen übrig
- die vielen teilweise sinnlosen globalen Variablen machen die Nutzung von C++
eigentlich überflüssig (soviel Objektorientierung wie hier bekommt man auch
mit C hin)
- teilweise sind sprachliche Elemente ungeschickt genutzt worden (z.B. diverse
gleiche if-Schleifen hintereinander), was den Code unübersichtlich macht
- Probleme mit dme Englischen (naja wir haben hier wohl noch ganz andere Probleme)
- Rückkehrcodes sind oft nicht eindeutig
- es gibt insgesamt drei Möglichkeiten der Fehlermeldung
- schlechte Trennung von Oberfläche und Funktionscode (gerade beim Interpetieren
problematisch)
- da explizit die Funktionsbenamung in der Aufgabenstellung angesprochen wurde,
ist dazu festzustellen, daß bis auf die Inkonsistenz von MDI/Mdi und GetPrivateProfileString
hier eigentlich keine Auffälligkeiten beim Patienten festzustellen sind ;-D
Als Vorschlag für die Zukunft wäre ein Tracetool evtl. interessant, welches
erkennt, wie die Funktionsaufrufe zusammenhängen und die Funktionsaufrufe entsprechend
einschiebt. Wenn also aus File A.cpp Funktion B die Funktion C aus File D.cpp
aufruft, so könnte es etwa so aussehen:
Aufgabe 6: Quellcodelokalisierung und Quellcodeanalyse
This document was generated using the LaTeX2HTML
translator Version 99.2beta6 (1.42)
Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning
Unit, University of Leeds.
Copyright © 1997, 1998, 1999, Ross Moore, Mathematics Department, Macquarie
University, Sydney.
The command line arguments were:
latex2html -no_subdir -split 0 -show_section_numbers /home/michael/SoftSan/trace1.tex
The translation was initiated by Michael Bell on 2001-01-10
Michael Bell
2001-01-10