Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

SPARK Ada - Formale Methoden (was: [OT])

11 views
Skip to first unread message

Vinzent Hoefler

unread,
Jan 27, 2003, 3:42:51 PM1/27/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

>Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
>>>
>>> Falls Du es 'vertrauenerweckend' findest,
>>> zu einem Berg von Quellcode, den Du nicht verstehst, noch einen ebenso
>>> unverständlichen Berg an Nathetik zu bekommen,
>>
>> [ ] Du hast SPARK verstanden.
>
>Ich habe mich solange durch die website gewühlt, bis ich unter der
>buzzword-Bergen das hier gefunden hatte:
>
> We formally specified the system using Z, coded it in SPARK
> Ada, and mathematically proved the specification and code of
> the safety critical functions.

Ich unterstreiche mal: "...mathematically proved the specification..."

> This project has shown that
> mathematical analysis of industrial scale software is
> practicable, giving the highest level of confidence in the
> correctness of the software.
>
>Angesichts der Tatsache, daß jedes Jahr Menschen sterben, weil andere
>sich verrechnet haben, mutet diese Aussage etwas seltsam an.

In der Praxis scheint das aber recht gut zu funktionieren, wenn ich
den Leuten von Lockheed-Martin und Boeing Glauben schenken darf.

Dagegen muten Aussagen wie

"Nicht wirklich. Korrektheitsbeweise sind prinzipiell redundant, denn
die Semantik einer Programmiersprache ist eindeutig definiert."
(<87n0lqw...@winter.inter-i.wohnheim.uni-mainz.de>)

und

"Falls jemand einen vetrackten logischen Fehler in einem Programm mit
mehreren parallellen Kontrolflüssen hat, der durch eine abartig
seltene Kombination fehlerhafter Eingabedaten ausgelöst wird, ist das
tolerabel (wenngleich ärgerlich)."
(<87n0lxjr...@winter.inter-i.wohnheim.uni-mainz.de>)

doch wesentlich komischer an.

Wenn ich das jetzt mal frei interpretiere, akzeptierst Du damit den
Tod von Menschen als aergerlich, aber tolerabel, waehrend es komisch
waere, doch wenigstens zu versuchen, zu beweisen, dass das von der
Software her (nahezu) ausgeschlossen werden kann, da das korrekte
Verhalten der Software ohnehin im Quellcode steht? :-)

Nein, ich halte auch vertrackte logische Fehler nicht fuer tolerabel.
Und Korrektheitsbeweise koennen solche Fehler sicher finden, wenn sie
ausserhalb der beschriebenen Spezifikation sind.

>Es bleibt
>auch unklar, wer mir die Äquivalenz dessen, was bewiesen wurde, mit
>dem Quelltext garantiert

Der SPARK-Examiner. Der Beweis *ist* der Quelltext. Es gibt keinen
zweiten Ordner mit vielen tollen Formeln dazu. Ein SPARK-Quelltext,
dessen Korrektheit (in erster Linie heisst das frei von
Laufzeitfehlern) nicht formal bewiesen werden kann, ist einfach kein
gueltiges SPARK-Programm.

>und warum beim Aufstellen des Beweise eine
>geringere Wahrscheinlichkeit für Fehler bestand, als beim Schreiben
>des Quellcodes.

Weil der Beweis auf formalen Methoden beruht, es duerfte von daher
wesentlich leichter sein, die moeglicherweise vorhandenen
Inkonsistenzen zu finden als das in einem beliebigen Quelltext der
Fall waere.

Da SPARK eben die Uebereinstimmung aller Pre- und Postconditions mit
dem Quellcode garantiert, ist letztendlich so ziemlich das einzige,
was Dir passieren kann, dass Du die Spezifikation falsch angibst oder
der Compiler nachher den Quellcode in den falschen Objektcode
umwandelt.

Wegen letzterem wird ja ueblicherweise noch die Uebereinstimmung des
Objektcodes mit dem Sourcecode gezeigt. Allerdings ist Boeing
mittlerweile eine Schritt weiter, indem sie sich von der FAA einen
speziellen Compiler (der recht SPARK-aehnlich ist) haben
zertifizieren[0] lassen koennen, der garantiert, dass er immer
Objektcode erzeugt, der der Semantik des Quellcodes entspricht. Somit
reicht dann der Beweise auf Source-Code-Ebene aus.

> I agree. Testing will always be essential no matter how
> efficient proof is, because of the limitations of what proof
> models.
> <URL:http://www.cs.york.ac.uk/hise/safety-critical-archive/2000/0504.html>

Ja. Unter anderem, weil eine Aequivalenz des Quelltextes mit der
Spezifikation nicht beweist, dass die Spezifikation das ist, was Du
wirklich haben moechtest.

Aus demselben Beitrag:

|The unit testing process was (at least comparatively) pretty
|inefficient and understanding that has certainly helped on other
|projects.

Unit-testing ist entfernt wohl das, was Du damit meintest:

"Ein Programm mit mehr als fünfhundert Zeilen besteht aus sauber
getrennten Subsystemen/ Modulen, die ausschließlich über
definierte Interfaces kommunizieren und deren Interna unterhalb einer
prozeduralen Spezifiaktion des Interfaces lokalisiert bleiben und
jeder einzelne dieser Teile ist klein genug, damit man ihn separat
debuggen kann."
(<87n0lxjr...@winter.inter-i.wohnheim.uni-mainz.de>)

So die Theorie und in den vielen Faellen mag das stimmen. Laut Rod
(und ich glaube da einfach mal seiner Erfahrung) findet man die
meisten Fehler aber, wenn man diese einzelnen Unit zusammenfuegen
will, also letztendlich im Interface. Das ist im uebrigen auch meine
Erfahrung.

Naja, den Rest des Absatzes quote ich einfach deshalb noch, weil Deine
Frage ja, IIRC, urspruenglich war, wer denn ueberhaupt Software formal
verifiziert:

|Also seeing the faults that the Z proof work found early on,
|especially in comparison with the effort it took, has personally
|made me much more likely to do such proof work in the future.

Wenn es Dich interessiert, kann ich Dir gerne auch mal die Zahlen
raussuchen, wieviele Fehler man in welcher Phase waehrend der
Entwicklung des MultOS-Kernels gefunden und beseitigt hat. IIRC haben
es von ~150 Fehlern nur vier ueberhaupt bis in die Testphase
geschafft. Und, das war es, was ich oben erwaehnte, eine nicht ganz
unerhebliche Zahl waren Fehler in der Spezifikation, die das
Verifikationssystem aufgedeckt hat.

>> >> >Nur für Spielzeugsprachen wie z.B. kleine Turingmaschinen mit nicht
>> >> >allzuviel Zuständen.
>> >>
>> >> Spielzeugsprache? http://www.sparkada.com
>> >
>> >Genauso klingt das.
>>
>> google SHOLIS
>
> * SPARK Language Features
> SPARK is a subset of the [13]Ada language. It includes Ada
> constructs regarded as essential for the construction of
> complex software, such as packages, private types, typed
> constants, functions with structured values, and the library
> system.

Was davon kann C? Packages kann man ja notfalls noch durch #include
substituieren. Demzufolge ist C fuer Dich eine Spielzeugsprache?

> It excludes tasks, exceptions, generic units, access
> types, use clauses, type aliasing, anonymous types, default
> values in record declarations, default subprogram parameters,
> goto statements, and declare statements.

C kennt keine Tasks (nachdem, was Rod Chapman im Dezember erzaehlt
hat, arbeiten PCS allerdings momentan an einem SPARK-System, dass das
Ravenscar-Profile erfuellen soll, somit waeren Tasks dort in der
naechsten Version enthalten), keine Exceptions (SPARK braucht keine,
da ja gerade die Abwesenheit von Laufzeitfehlern bewiesen wird) und
auch keine Generics. Das einzige, was Dir fehlt, sind gotos (braucht
man die?) und access-types, sprich (dynamische) pointer und das ist
nicht wirklich ein Verlust, da in C Zeiger eher zu extensiv auch in
statischen Zusammenhaengen benoetigt werden. Der Rest ist
ausschliesslich syntactic sugar.

Was ich mit SHOLIS meinte: Wenn mit SPARK ein System beschreiben kann,
welches die sicherheitskritische Software eines Helikopters darstellt,
kann man das wohl kaum als Spielzeugsprache ansehen. Das Teil fliegt
ausserhalb von Kinderzimmern.

Lockheed-Martin nutzte das in der Hercules-C130J und sie behaupten,
damit 80% der Entwicklungskosten gegenueber herkoemmlichen Methoden
gespart haben zu koennen und vor allem: "It worked from the first
time."

Da wir damit in de.comp.lang.c aber nun wirklich ziemlich gruendlich
OT sind, wuerde ich das ganze mal nach de.comp.lang.misc crossposten
und gleichzeitig auch das F'up nach dorthin vorschlagen.


Vinzent.


[0] Um mal einen Eindruck davon zu bekommen, was FAA-Zertifizierung
bedeutet, der Mensch von Boeing sprach von IIRC, ueber 2000 (in
Worten: zweitausend) Unterschriften, die im Laufe des
Zertifizierungsprozesses benoetigt wurden. Aber ich kann die Papers
gern noch mal raussuchen.

Florian Weimer

unread,
Jan 27, 2003, 6:37:58 PM1/27/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:

> Ich unterstreiche mal: "...mathematically proved the
> specification..."

Warum? Weil es Quatsch ist? ;-)

Vinzent Hoefler

unread,
Jan 27, 2003, 6:45:48 PM1/27/03
to
Florian Weimer <f...@deneb.enyo.de> wrote:

>Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>
>> Ich unterstreiche mal: "...mathematically proved the
>> specification..."
>
>Warum?

Weil damit nicht bewiesen ist, dass die Spezifikation korrekt ist?

>Weil es Quatsch ist? ;-)

Inwiefern? Man sollte das vielleicht nicht ganz aus dem Zusammenhang
reissen.


Vinzent.

Rainer Weikusat

unread,
Jan 28, 2003, 5:38:16 AM1/28/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
> >Ich habe mich solange durch die website gewühlt, bis ich unter der
> >buzzword-Bergen das hier gefunden hatte:
> >
> > We formally specified the system using Z, coded it in SPARK
> > Ada, and mathematically proved the specification and code of
> > the safety critical functions.
>
> Ich unterstreiche mal: "...mathematically proved the
> specification..."

Wozu?

[...]

> >Angesichts der Tatsache, daß jedes Jahr Menschen sterben, weil andere
> >sich verrechnet haben, mutet diese Aussage etwas seltsam an.
>
> In der Praxis scheint das aber recht gut zu funktionieren, wenn ich
> den Leuten von Lockheed-Martin und Boeing Glauben schenken darf.
>
> Dagegen muten Aussagen wie
>
> "Nicht wirklich. Korrektheitsbeweise sind prinzipiell redundant, denn
> die Semantik einer Programmiersprache ist eindeutig definiert."
> (<87n0lqw...@winter.inter-i.wohnheim.uni-mainz.de>)
>
> und
>
> "Falls jemand einen vetrackten logischen Fehler in einem Programm mit
> mehreren parallellen Kontrolflüssen hat, der durch eine abartig
> seltene Kombination fehlerhafter Eingabedaten ausgelöst wird, ist das
> tolerabel (wenngleich ärgerlich)."
> (<87n0lxjr...@winter.inter-i.wohnheim.uni-mainz.de>)
>
> doch wesentlich komischer an.
>
> Wenn ich das jetzt mal frei interpretiere, akzeptierst Du damit den
> Tod von Menschen als aergerlich, aber tolerabel,

Lieber Vinzent, ich glaube, ich lege Maßstäbe an Software an, die Du
Dir noch nicht einmal vorstellen kannst.

> waehrend es komisch waere, doch wenigstens zu versuchen, zu
> beweisen, dass das von der Software her (nahezu) ausgeschlossen
> werden kann, da das korrekte Verhalten der Software ohnehin im
> Quellcode steht?

Falls Du zum Verständnis des Quellcodes irgendetwas anderes außer dem
Quellcode benötigst darfst Du aufhören, Dir darüber Sorgen zu machen.

> Nein, ich halte auch vertrackte logische Fehler nicht fuer tolerabel.
> Und Korrektheitsbeweise koennen solche Fehler sicher finden, wenn sie
> ausserhalb der beschriebenen Spezifikation sind.

«There's a killer on the loose again».

> >Es bleibt auch unklar, wer mir die Äquivalenz dessen, was bewiesen
> >wurde, mit dem Quelltext garantiert
>
> Der SPARK-Examiner. Der Beweis *ist* der Quelltext. Es gibt keinen
> zweiten Ordner mit vielen tollen Formeln dazu. Ein SPARK-Quelltext,
> dessen Korrektheit (in erster Linie heisst das frei von
> Laufzeitfehlern) nicht formal bewiesen werden kann, ist einfach kein
> gueltiges SPARK-Programm.

Normale Leute nennen sowas einen Zirkelschluß.

> >und warum beim Aufstellen des Beweise eine geringere
> >Wahrscheinlichkeit für Fehler bestand, als beim Schreiben des
> >Quellcodes.
>
> Weil der Beweis auf formalen Methoden beruht,
> es duerfte von daher wesentlich leichter sein, die moeglicherweise
> vorhandenen Inkonsistenzen zu finden als das in einem beliebigen
> Quelltext der Fall waere.

Vertrau mir: "Engineers learn quickly how to avoid warnings" wird von
fünf von zehn Fällen "den Kommentar kann ich grade nicht brauchen"
heißen.

> Unit-testing ist entfernt wohl das, was Du damit meintest:
>
> "Ein Programm mit mehr als fünfhundert Zeilen besteht aus sauber
> getrennten Subsystemen/ Modulen, die ausschließlich über
> definierte Interfaces kommunizieren und deren Interna unterhalb einer
> prozeduralen Spezifiaktion des Interfaces lokalisiert bleiben und
> jeder einzelne dieser Teile ist klein genug, damit man ihn separat
> debuggen kann."
> (<87n0lxjr...@winter.inter-i.wohnheim.uni-mainz.de>)
>
> So die Theorie und in den vielen Faellen mag das stimmen. Laut Rod
> (und ich glaube da einfach mal seiner Erfahrung) findet man die
> meisten Fehler aber, wenn man diese einzelnen Unit zusammenfuegen
> will, also letztendlich im Interface. Das ist im uebrigen auch meine
> Erfahrung.

Das ist eine groteskte Horrortheorie, deren Implikationen
ausschließlich besagen, daß die Resultate lebensgefährlich sein
werden.

> Wenn es Dich interessiert, kann ich Dir gerne auch mal die Zahlen
> raussuchen, wieviele Fehler man in welcher Phase waehrend der
> Entwicklung des MultOS-Kernels gefunden und beseitigt hat.

Bitte nicht. Ich denke ohnehin schon darüber nach, sofort zum
militanten Technikfeind zu werden.

> >> >> Spielzeugsprache? http://www.sparkada.com
> >> >
> >> >Genauso klingt das.
> >>
> >> google SHOLIS
> >
> > * SPARK Language Features
> > SPARK is a subset of the [13]Ada language. It includes Ada
> > constructs regarded as essential for the construction of
> > complex software, such as packages, private types, typed
> > constants, functions with structured values, and the library
> > system.
>
> Was davon kann C?

Was kann man damit ausdrücken, das man nicht in jeder
turing-vollständigen Sprache ausdrücken kann?

[...]

> keine Exceptions (SPARK braucht keine, da ja gerade die Abwesenheit
> von Laufzeitfehlern bewiesen wird)

In einem System mit mechanischen Komponenten?

> und auch keine Generics.

> Das einzige, was Dir fehlt, sind gotos (braucht
> man die?)

«Man» benutzt sie ständig, was vom Compiler mehr oder minder hinter
einem Feigenblatt verborgen wird.

> und access-types, sprich (dynamische) pointer und das ist
> nicht wirklich ein Verlust, da in C Zeiger eher zu extensiv auch in
> statischen Zusammenhaengen benoetigt werden.

Obiges gilt entsprechend: Objekte im RAM haben eine Adresse, die die
CPU benutzt, um sie zu adressieren.

> Was ich mit SHOLIS meinte: Wenn mit SPARK ein System beschreiben kann,
> welches die sicherheitskritische Software eines Helikopters
> darstellt,

Es ist «bewiesen», daß man so ein System in Visual Basic beschreiben
kann.

Stefan Nobis

unread,
Jan 28, 2003, 8:58:32 AM1/28/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> Was kann man damit ausdrücken, das man nicht in jeder
> turing-vollständigen Sprache ausdrücken kann?

(Komplexere) Abstraktionen und (konzeptionelle) Zusammenhänge.

Wenn alles, was man für komplexere Programme benötigen würde, eine
beliebige turing-vollständige Sprache wäre, wäre C totaler Overkill. C
unterstützt schon eine Menge Abstraktionen, die für
Turing-Vollständigkeit vollkommen überflüssig sind.

Ist C also bloatig? Nein? Wo genau ist dann die Grenze von sinnvollen
Abstraktionen? It depends? Ah, und warum dann nicht Sprachen
verwenden, die mehr Abstraktionsmittel als C zur Verfügung stellen
(sofern man sie benötigt!)?

--
Stefan.

Georg Bauhaus

unread,
Jan 28, 2003, 10:23:34 AM1/28/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

: Falls Du zum Verst?ndnis des Quellcodes irgendetwas anderes au?er dem
: Quellcode ben?tigst darfst Du aufh?ren, Dir dar?ber Sorgen zu machen.

Ich weiss nicht ob ich den worueber-Bezug aufloesen konnte. Sonst:
Definiere die Wirkung von ":=" in a := b, a und b Referenzen auf Instanzen
konformer Typen in einer Sprache deiner Wahl, mit vordefiniertem ":=".
Schnell, ohne Blick in Handbuecher. Du musst das Programm pruefen, weil
eine Fehlfunktion entdeckt wurde. Formale Hilfsmittel sind nicht zu
gelassen.

:> Weil der Beweis auf formalen Methoden beruht,


:> es duerfte von daher wesentlich leichter sein, die moeglicherweise
:> vorhandenen Inkonsistenzen zu finden als das in einem beliebigen
:> Quelltext der Fall waere.
:
: Vertrau mir: "Engineers learn quickly how to avoid warnings" wird von

: f?nf von zehn F?llen "den Kommentar kann ich grade nicht brauchen"
: hei?en.

Das wird schnell anders, wenn die "Engineers" mit persoenlichen
Folgen rechnen muessen. Der Kommentar sagt nichts dazu, ob formale
MEthoden erleichtern, erschweren, ... ?

:> Laut Rod


:> (und ich glaube da einfach mal seiner Erfahrung) findet man die
:> meisten Fehler aber, wenn man diese einzelnen Unit zusammenfuegen
:> will, also letztendlich im Interface.
:

: Das ist eine groteskte Horrortheorie,

Hm. Warum?

: deren Implikationen : ausschlie?lich besagen, da? die Resultate
: lebensgef?hrlich sein werden.

Deine Loesung ist ___?


:> Was davon kann C?
:
: Was kann man damit ausdr?cken, das man nicht in jeder
: turing-Vollst?ndigen Sprache ausdr?cken kann?

{ (ascii + 72),
(ascii + 105),
(ascii + 108),
(ascii + 102),
(ascii + 114),
(ascii + 101),
(ascii + 105),
(ascii + 99),
(ascii + 104),
(ascii + 101),
(ascii + 115)
}

Jedes turing-vollstaendige setup koennte Speichersammlung
bereitstellen. Wer/was schuetzt die Steuerung des Roentgen-Kastens
davor, dass das jemand versehentlich genutzt hat?

:> Das einzige, was Dir fehlt, sind gotos (braucht
:> man die?)

: ?Man? benutzt sie st?ndig, was vom Compiler mehr oder minder hinter
: einem Feigenblatt verborgen wird.

Sicher, aber "compiler" != "man".

: Obiges gilt entsprechend: Objekte im RAM haben eine Adresse, die die


: CPU benutzt, um sie zu adressieren.

Was ueberlegen laesst, dass CPUs indirekte Adressierung ueber
Bereichs-Tabellen benutzten koennten, und die koennten ja auch kaputt
sein, wegen Hardware-Fehlers... Nur, was bedeutet das fuer das
Formulieren von Programmen in Hochsprache X?

Die Behauptungen, die in einem Programm-Quelltext enthalten sind,
koennen glaube ich ohne Gesichtsverlust explizit gemacht werden,
zum Nutzen derer, die es nutzen, oder warten, oder pruefen.
Das kann die Autoren selber betreffen.

Schliesslich hat nicht jeder die vollstaendige Sprachdefinition
der Sprache X im Kopf, geschweige denn jede Herleitung zur Loesung
einer Sprachfrage.

: Es ist ?bewiesen?, da? man so ein System in Visual Basic beschreiben
: kann.

Welche Laufzeit-Umgebung wird von Miscrosoft fuer Echtzeit-STeuerungen
verkauf? (Egal ob VB, C#, C++, Fortran...)
Wie geht Bit-Adressierung auf Sparc-CPUs mit Visual-Basic?

Ich bin sicher, dass es moeglich ist, in einer konkreten Prolog-Variante
eine Motor-Steuerung zu beschreiben, bleibt aber zu beurteilen,
ob das in endlicher Zeit moeglich ist, ob es ueberschaubar bleibt,
und m.a.W. ob das je verwirklicht werden kann, in einem Forschungs-Labor
oder bei einem Kfz-Hersteller.

Aehnliches ist mit Haskell und Ada probiert worden. Ja, es ist moeglich
in Haskell praktischerweise reaktive Systeme sauber zu beschreiben,
zu simulieren.
Nein, es ist derzeit nicht moeglich, etwas Anderes als ein lauffaehiges,
aber zu langsames, zu viel Speicher benoetigendes Modell damit zu erzeugen
(in der echten Welt).

Gruesse,
Georg

Vinzent Hoefler

unread,
Jan 28, 2003, 10:55:17 AM1/28/03
to
Rainer Weikusat wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
>> >Ich habe mich solange durch die website gewühlt, bis ich unter der
>>

>> Ich unterstreiche mal: "...mathematically proved the
>> specification..."
>
> Wozu?

Das hatte ich weiter unten ausgefuehrt.

>> Wenn ich das jetzt mal frei interpretiere, akzeptierst Du damit den
>> Tod von Menschen als aergerlich, aber tolerabel,
>
> Lieber Vinzent, ich glaube, ich lege Maßstäbe an Software an, die Du
> Dir noch nicht einmal vorstellen kannst.

Ehrlich gesagt, das *will* ich mir auch gar nicht vorstellen.

>> waehrend es komisch waere, doch wenigstens zu versuchen, zu
>> beweisen, dass das von der Software her (nahezu) ausgeschlossen
>> werden kann, da das korrekte Verhalten der Software ohnehin im
>> Quellcode steht?
>
> Falls Du zum Verständnis des Quellcodes irgendetwas anderes außer dem
> Quellcode benötigst darfst Du aufhören, Dir darüber Sorgen zu machen.

Das Verstaendnis des Quellcodes sagt nichts ueber seine Korrektheit aus.
Und es wohl kaum moeglich, ein 100'000 Zeilen-Programm vollstaendig zu
verstehen und garantieren zu koennen, dass es das tut, was es tun soll,
unter allen Umstaenden.

>> Nein, ich halte auch vertrackte logische Fehler nicht fuer tolerabel.
>> Und Korrektheitsbeweise koennen solche Fehler sicher finden, wenn sie
>> ausserhalb der beschriebenen Spezifikation sind.
>
> «There's a killer on the loose again».

Was willst Du damit sagen? It is easier to fit the specification to a
program than vice versa?

>> >Es bleibt auch unklar, wer mir die Äquivalenz dessen, was bewiesen
>> >wurde, mit dem Quelltext garantiert
>>
>> Der SPARK-Examiner. Der Beweis *ist* der Quelltext. Es gibt keinen
>> zweiten Ordner mit vielen tollen Formeln dazu. Ein SPARK-Quelltext,
>> dessen Korrektheit (in erster Linie heisst das frei von
>> Laufzeitfehlern) nicht formal bewiesen werden kann, ist einfach kein
>> gueltiges SPARK-Programm.
>
> Normale Leute nennen sowas einen Zirkelschluß.

Und Leute, die sich ein klein wenig mit diesen Methoden beschaeftigt
haben, wissen, dass die SPARK-Annotations nicht den ausfuehrenden Code
darstellen. Ja, es ist redundant, nachdem der Examiner festgestellt
hat, dass beides korreliert.

>> Weil der Beweis auf formalen Methoden beruht,
>> es duerfte von daher wesentlich leichter sein, die moeglicherweise
>> vorhandenen Inkonsistenzen zu finden als das in einem beliebigen
>> Quelltext der Fall waere.
>
> Vertrau mir: "Engineers learn quickly how to avoid warnings" wird von
> fünf von zehn Fällen "den Kommentar kann ich grade nicht brauchen"
> heißen.

Tja, dann haben diese 50% ihren Beruf verfehlt.

Du stimmst mir also zu, dass Fehler im Quellcode wesentlich schwerer zu
finden sind als im Zuge einer formalen Beschreibung?

>> Unit-testing ist entfernt wohl das, was Du damit meintest:
>>
>> "Ein Programm mit mehr als fünfhundert Zeilen besteht aus sauber
>> getrennten Subsystemen/ Modulen, die ausschließlich über
>> definierte Interfaces kommunizieren und deren Interna unterhalb einer
>> prozeduralen Spezifiaktion des Interfaces lokalisiert bleiben und
>> jeder einzelne dieser Teile ist klein genug, damit man ihn separat
>> debuggen kann."
>> (<87n0lxjr...@winter.inter-i.wohnheim.uni-mainz.de>)
>>
>> So die Theorie und in den vielen Faellen mag das stimmen. Laut Rod
>> (und ich glaube da einfach mal seiner Erfahrung) findet man die
>> meisten Fehler aber, wenn man diese einzelnen Unit zusammenfuegen
>> will, also letztendlich im Interface. Das ist im uebrigen auch meine
>> Erfahrung.
>
> Das ist eine groteskte Horrortheorie,

Diese Theorie stammt von Dir, danke. Oder meintest Du eher:

IEEE Software Vol. 19, No. 1, Jan/Feb 2002:

"Traditionally critical-systems testings is very expensive. A reason for
this is that testing occurs several times: we test indivisual units,
integrate them and test the integration, and then the system as whole.
Our experience with previous safety-critical projects suggests that
this approach is inefficient and particularly that unit testing is
ineffective because most errors are interface errors, not internal
errors in units. It is expensive because we must build test harnesses
to test units in isolation."

> deren Implikationen
> ausschließlich besagen, daß die Resultate lebensgefährlich sein
> werden.

Interessant. Wie kommst Du darauf?

>> Wenn es Dich interessiert, kann ich Dir gerne auch mal die Zahlen
>> raussuchen, wieviele Fehler man in welcher Phase waehrend der
>> Entwicklung des MultOS-Kernels gefunden und beseitigt hat.
>
> Bitte nicht.

Sicher? Es sind uebrigens ein paar mehr als ich in Erinnerung hatte.

> Ich denke ohnehin schon darüber nach, sofort zum
> militanten Technikfeind zu werden.

Tu das.

>> >> >> Spielzeugsprache? http://www.sparkada.com
[...]
>> > * SPARK Language Features
[...]


>>
>> Was davon kann C?
>
> Was kann man damit ausdrücken, das man nicht in jeder
> turing-vollständigen Sprache ausdrücken kann?

Eine Registermaschine ist auch turing-vollstaendig. Warum also C? Ich
bin immer noch nicht ganz dahintergekommen, was Du mit Spielzeugsprache
meinst.

Eine Sprache, die es einfacher macht, korrekten Code zu schreiben, weil
das dann ja jedes Kind tun kann? Dein Problem, ich schreibe keine
Software, um mit Compiler und Debugger zu kaempfen, ich schreibe
Software, um etwas zum Laufen zu bekommen.

>> keine Exceptions (SPARK braucht keine, da ja gerade die Abwesenheit
>> von Laufzeitfehlern bewiesen wird)
>
> In einem System mit mechanischen Komponenten?

In der Software? Ja.

>> und auch keine Generics.
>
>> Das einzige, was Dir fehlt, sind gotos (braucht
>> man die?)
>
> «Man» benutzt sie ständig, was vom Compiler mehr oder minder hinter
> einem Feigenblatt verborgen wird.

*Das* weiss ich selbst.

>> und access-types, sprich (dynamische) pointer und das ist
>> nicht wirklich ein Verlust, da in C Zeiger eher zu extensiv auch in
>> statischen Zusammenhaengen benoetigt werden.
>
> Obiges gilt entsprechend: Objekte im RAM haben eine Adresse, die die
> CPU benutzt, um sie zu adressieren.

Und? Deswegen muss ich das Objekt auf Source-Ebene nicht mit seiner
Adresse ansprechen.

Da kannst Du auch gleich wieder Assembler programmieren.

>> Was ich mit SHOLIS meinte: Wenn mit SPARK ein System beschreiben
>> kann, welches die sicherheitskritische Software eines Helikopters
>> darstellt,
>
> Es ist «bewiesen», daß man so ein System in Visual Basic beschreiben
> kann.

So, kann man das? Welches Zeitfenster setzt Du an bis zur Zertifikation
nach DO-178B und/oder ITSEC E6?


Vinzent.

--
Getting an education at the University of California is like having
$50.00 shoved up your ass, a nickel at a time.

Rainer Weikusat

unread,
Jan 28, 2003, 10:58:15 AM1/28/03
to
Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
> : Falls Du zum Verst?ndnis des Quellcodes irgendetwas anderes au?er dem
> : Quellcode ben?tigst darfst Du aufh?ren, Dir dar?ber Sorgen zu machen.
>
> Ich weiss nicht ob ich den worueber-Bezug aufloesen konnte. Sonst:
> Definiere die Wirkung von ":=" in a := b, a und b Referenzen auf Instanzen
> konformer Typen in einer Sprache deiner Wahl, mit vordefiniertem ":=".
> Schnell, ohne Blick in Handbuecher. Du musst das Programm pruefen, weil
> eine Fehlfunktion entdeckt wurde. Formale Hilfsmittel sind nicht zu
> gelassen.

In allen Sprachen, die ich verwende, ist := ein
Syntaxfehler. Dokumentation benutzt man im übrigen zum Nachschlagen,
denn dafür ist sie da. Ich muß allerdings gestehen, Dir nicht ganz
folgen zu können.

> :> Laut Rod
> :> (und ich glaube da einfach mal seiner Erfahrung) findet man die
> :> meisten Fehler aber, wenn man diese einzelnen Unit zusammenfuegen
> :> will, also letztendlich im Interface.
> :
> : Das ist eine groteskte Horrortheorie,
>
> Hm. Warum?

Vielleicht sollte man es zur grotesken Horror-Realität aufwerten ...

> :> Was davon kann C?
> :
> : Was kann man damit ausdr?cken, das man nicht in jeder
> : turing-Vollst?ndigen Sprache ausdr?cken kann?
>
> { (ascii + 72),
> (ascii + 105),
> (ascii + 108),
> (ascii + 102),
> (ascii + 114),
> (ascii + 101),
> (ascii + 105),
> (ascii + 99),
> (ascii + 104),
> (ascii + 101),
> (ascii + 115)
> }
>
> Jedes turing-vollstaendige setup koennte Speichersammlung
> bereitstellen. Wer/was schuetzt die Steuerung des Roentgen-Kastens
> davor, dass das jemand versehentlich genutzt hat?

Wovon sprichst Du?

> :> Das einzige, was Dir fehlt, sind gotos (braucht
> :> man die?)
>
> : ?Man? benutzt sie st?ndig, was vom Compiler mehr oder minder hinter
> : einem Feigenblatt verborgen wird.
>
> Sicher, aber "compiler" != "man".

Der Compiler tut aber nichts von alleine.

> Die Behauptungen, die in einem Programm-Quelltext enthalten sind,
> koennen glaube ich ohne Gesichtsverlust explizit gemacht werden,

Sie sind es bereits.

> zum Nutzen derer, die es nutzen, oder warten, oder pruefen.
> Das kann die Autoren selber betreffen.

Das nützt nichts: Wenn Du den Quellcode verändern möchtest, mußt Du
den vorher gelesen und verstanden haben.

Rainer Weikusat

unread,
Jan 28, 2003, 11:02:37 AM1/28/03
to
Stefan Nobis <ste...@snobis.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
> > Was kann man damit ausdrücken, das man nicht in jeder
> > turing-vollständigen Sprache ausdrücken kann?
>
> (Komplexere) Abstraktionen und (konzeptionelle) Zusammenhänge.
>
> Wenn alles, was man für komplexere Programme benötigen würde, eine
> beliebige turing-vollständige Sprache wäre, wäre C totaler Overkill. C
> unterstützt schon eine Menge Abstraktionen, die für
> Turing-Vollständigkeit vollkommen überflüssig sind.

Und?

> Ist C also bloatig? Nein? Wo genau ist dann die Grenze von sinnvollen
> Abstraktionen?

Es ging um notwendige Abstraktionen.

> It depends? Ah, und warum dann nicht Sprachen verwenden, die mehr
> Abstraktionsmittel als C zur Verfügung stellen (sofern man sie
> benötigt!)?

Weil einem diese Dinge real auch ohne spezifischen language support
zur Verfügung stehen.

Vinzent Hoefler

unread,
Jan 28, 2003, 11:43:09 AM1/28/03
to
Rainer Weikusat wrote:

> Stefan Nobis <ste...@snobis.de> writes:
>> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
>>
>> Ist C also bloatig? Nein? Wo genau ist dann die Grenze von sinnvollen
>> Abstraktionen?
>
> Es ging um notwendige Abstraktionen.

Wo genau ist die Grenze zwischen sinnvoll und notwendig? Die absolut
untere Grenze duerfte jedenfalls bei der Abstraktion Maschinencode ->
Mnemonic zu liegen.

>> It depends? Ah, und warum dann nicht Sprachen verwenden, die mehr
>> Abstraktionsmittel als C zur Verfügung stellen (sofern man sie
>> benötigt!)?
>
> Weil einem diese Dinge real auch ohne spezifischen language support
> zur Verfügung stehen.

Und alle Sprachen, die mehr Features als C zur Verfuegung stellen, sind
demzufolge Spielzeugsprachen? Ich kann Dir nicht ganz folgen, aber
bitte:

|function Get_Speed (Distance : in Meter;
| Time : in Seconds) return Speed;

Natuerlich *kann* man in C selbst darauf achten, dass man die Funktion
immer mit den richtigen Parametern aufruft und dass der Aufruf dieser
Funktion keine Seiteneffekte hat.

Aber warum sollte ich das auch noch muessen? Ich habe durchaus besseres
zu tun.


Vinzent.

--
Why is it that there are so many more horses' asses than there are
horses?
-- G. Gordon Liddy

Lutz Donnerhacke

unread,
Jan 28, 2003, 11:56:58 AM1/28/03
to
* Vinzent Hoefler wrote:
> Natuerlich *kann* man in C selbst darauf achten, dass man die Funktion
> immer mit den richtigen Parametern aufruft und dass der Aufruf dieser
> Funktion keine Seiteneffekte hat.

Viel schlimmer ist es, jedesmal wieder das korrekte Taskingverhalten zu
implementieren. Klar, kann man das in Bibliotheken auslagern, aber ist das
dann noch C? Nein, die Bibliotheken gehören nicht zur Sprache, können also
nicht benutzt werden. Oder müssen selbst verifiziert werden.

Rainer Weikusat

unread,
Jan 28, 2003, 12:16:06 PM1/28/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Rainer Weikusat wrote:
> > Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> >> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
> >> >Ich habe mich solange durch die website gewühlt, bis ich unter der
> >>
> >> Ich unterstreiche mal: "...mathematically proved the
> >> specification..."
> >
> > Wozu?
>
> Das hatte ich weiter unten ausgefuehrt.

Das muß mir dann entgangen sein.

> >> Wenn ich das jetzt mal frei interpretiere, akzeptierst Du damit den
> >> Tod von Menschen als aergerlich, aber tolerabel,
> >
> > Lieber Vinzent, ich glaube, ich lege Maßstäbe an Software an, die Du
> > Dir noch nicht einmal vorstellen kannst.
>
> Ehrlich gesagt, das *will* ich mir auch gar nicht vorstellen.

Dann bleibt zu hoffen, daß Dich jemand aus dem Verkehr zieht, bevor Du
wegen gemeingefährlicher Lernresistenz ein paar Menschen auf dem
Gewissen hast. Tut mir leid, aber das ist definitiv nicht mehr
komisch.

> >> waehrend es komisch waere, doch wenigstens zu versuchen, zu
> >> beweisen, dass das von der Software her (nahezu) ausgeschlossen
> >> werden kann, da das korrekte Verhalten der Software ohnehin im
> >> Quellcode steht?
> >
> > Falls Du zum Verständnis des Quellcodes irgendetwas anderes außer dem
> > Quellcode benötigst darfst Du aufhören, Dir darüber Sorgen zu machen.
>
> Das Verstaendnis des Quellcodes sagt nichts ueber seine Korrektheit
> aus.

Das «Verständnis» sagt per se gar nichts aus. Aber der Quelltext tut
das: Er ist eine vollständige Beschreibung dessen, was die Software zur
Laufzeit tun wird.

> Und es wohl kaum moeglich, ein 100'000 Zeilen-Programm vollstaendig zu
> verstehen und garantieren zu koennen, dass es das tut, was es tun soll,
> unter allen Umstaenden.

Es ist möglich, eine 100.000-Zeilen-Programm so zu konstruieren, daß
man keine Einheiten von mehr als maximal tausend Zeilen hat und so,
daß diese Einheiten keine internen Abhängigkeiten haben.

> >> Nein, ich halte auch vertrackte logische Fehler nicht fuer tolerabel.
> >> Und Korrektheitsbeweise koennen solche Fehler sicher finden, wenn sie
> >> ausserhalb der beschriebenen Spezifikation sind.
> >
> > «There's a killer on the loose again».
>
> Was willst Du damit sagen?

Die Grundvoraussetung für das, was ich geschrieben hatte
(«Tolerabilität von fringe case-Fehlersituationen»), ist, daß das
System deswegen nicht Amok läuft, was man durch einen geeigneten
internen Aufbau sicherstellt. Wenn das für Dich nicht
selbstverständlich ist, und diesen Eindruck erweckst Du gerade, bist
Du eine Gefahr für Deine Umgebung, deren Umfang ausschließlich von dem
Gefahrenpotential dessen, womit man Dich herumspielen läßt, limitiert
wird.

> It is easier to fit the specification to a program than vice versa?

Entweder das Programm ist eine Übersetzung der Spezifikation in eine
andere Sprache oder Du hast einen schrecklichen Fehler gemacht, der
sich auch mit 400t glue code im Nachhinein nicht mehr wird
reparieren lassen.

> >> >Es bleibt auch unklar, wer mir die Äquivalenz dessen, was bewiesen
> >> >wurde, mit dem Quelltext garantiert
> >>
> >> Der SPARK-Examiner. Der Beweis *ist* der Quelltext. Es gibt keinen
> >> zweiten Ordner mit vielen tollen Formeln dazu. Ein SPARK-Quelltext,
> >> dessen Korrektheit (in erster Linie heisst das frei von
> >> Laufzeitfehlern) nicht formal bewiesen werden kann, ist einfach kein
> >> gueltiges SPARK-Programm.
> >
> > Normale Leute nennen sowas einen Zirkelschluß.
>
> Und Leute, die sich ein klein wenig mit diesen Methoden beschaeftigt
> haben, wissen, dass die SPARK-Annotations nicht den ausfuehrenden Code
> darstellen. Ja, es ist redundant, nachdem der Examiner festgestellt
> hat, dass beides korreliert.

Lediglich wird von dem nicht erwartet, tatsächlich alle Fehler zu
finden, sondern bloß alle möglichen Fehler. Der Rest wird dann wieder
dem Programmierer überlassen. Falls man dem vorher nicht zutrauen
konnte, faktisch korrekten Code zu schreiben (insofern möglich), warum
sollte er es hinterher plötzlich können?

> >> Weil der Beweis auf formalen Methoden beruht,
> >> es duerfte von daher wesentlich leichter sein, die moeglicherweise
> >> vorhandenen Inkonsistenzen zu finden als das in einem beliebigen
> >> Quelltext der Fall waere.
> >
> > Vertrau mir: "Engineers learn quickly how to avoid warnings" wird von
> > fünf von zehn Fällen "den Kommentar kann ich grade nicht brauchen"
> > heißen.
>
> Tja, dann haben diese 50% ihren Beruf verfehlt.
>
> Du stimmst mir also zu, dass Fehler im Quellcode wesentlich schwerer zu
> finden sind als im Zuge einer formalen Beschreibung?

Wie käme ich denn dazu? Wegen einer formalen Beschreibung ohne Fehler
bekomme ich keinen Quelltext ohne Fehler, und (zum 1000x): Ein
Programm ist bereits eine formale Beschreibung.

> >> Unit-testing ist entfernt wohl das, was Du damit meintest:
> >>
> >> "Ein Programm mit mehr als fünfhundert Zeilen besteht aus sauber
> >> getrennten Subsystemen/ Modulen, die ausschließlich über
> >> definierte Interfaces kommunizieren und deren Interna unterhalb einer
> >> prozeduralen Spezifiaktion des Interfaces lokalisiert bleiben und
> >> jeder einzelne dieser Teile ist klein genug, damit man ihn separat
> >> debuggen kann."
> >> (<87n0lxjr...@winter.inter-i.wohnheim.uni-mainz.de>)
> >>
> >> So die Theorie und in den vielen Faellen mag das stimmen. Laut Rod
> >> (und ich glaube da einfach mal seiner Erfahrung) findet man die
> >> meisten Fehler aber, wenn man diese einzelnen Unit zusammenfuegen
> >> will, also letztendlich im Interface. Das ist im uebrigen auch meine
> >> Erfahrung.
> >
> > Das ist eine groteskte Horrortheorie,
>
> Diese Theorie stammt von Dir, danke.

Warum sollte ich mich denn vollkommen widersinnig auf meinen Text
beziehen anstelle auf Deinen?

> Oder meintest Du eher:
>
> IEEE Software Vol. 19, No. 1, Jan/Feb 2002:
>
> "Traditionally critical-systems testings is very expensive. A reason for
> this is that testing occurs several times: we test indivisual units,
> integrate them and test the integration, and then the system as whole.
> Our experience with previous safety-critical projects suggests that
> this approach is inefficient and particularly that unit testing is
> ineffective because most errors are interface errors, not internal
> errors in units.

Bei allen Dingen, mit denen ich praktisch zu tun habe, und dazu gehört
Quellcode anderer Leute mit dazu, verhält sich das genau umgekehrt, dh
der Code tut nicht das, was das Interface angeblich bereitstellt.

> > deren Implikationen ausschließlich besagen, daß die Resultate
> > lebensgefährlich sein werden.
>
> Interessant. Wie kommst Du darauf?

Ich denke nicht, daß ich das Dir in einem Usenet-angemessenen Rahmen
erklären kann, aber jedenfalls würde ich nie so wahnsinnig sein, mein
Leben einem Computerprogramm anzuvertrauen, auf das diese Aussage
zutrifft, falls ich nicht ohnehin Hazard spiele.

> Tu das.
>
> >> >> >> Spielzeugsprache? http://www.sparkada.com
> [...]
> >> > * SPARK Language Features
> [...]
> >>
> >> Was davon kann C?
> >
> > Was kann man damit ausdrücken, das man nicht in jeder
> > turing-vollständigen Sprache ausdrücken kann?
>
> Eine Registermaschine ist auch turing-vollstaendig. Warum also C?

C-Programme beschreiben normalerweise Registermaschinen.

> Ich bin immer noch nicht ganz dahintergekommen, was Du mit
> Spielzeugsprache meinst.

ZB eine ohne dynamische Speicherverwaltung und ohne
Rekursionen. Insbesondere letzteres mutet abstrus an, denn gerade
rekursive Algorithmen kann man oft einfach durch Induktion beweisen.

> Eine Sprache, die es einfacher macht, korrekten Code zu schreiben,
> weil das dann ja jedes Kind tun kann?

Wie bereits erwähnt: Ich möchte nicht mein Leben einem Programm von
jemandem anvertrauen, dem es «kompliziert» erscheint,
integer-Überläufe im Quelltext sinnvoll zu behandeln und der ein
Spezialtool braucht, um potentielle zu finden. Dazu gibt es zuviele
esoterische Fehlermöglichkeiten.

> Dein Problem, ich schreibe keine Software, um mit Compiler und
> Debugger zu kaempfen, ich schreibe Software, um etwas zum Laufen zu
> bekommen.

Vermutlich wäre «davonlaufen» anzuraten.

> >> Das einzige, was Dir fehlt, sind gotos (braucht
> >> man die?)
> >
> > «Man» benutzt sie ständig, was vom Compiler mehr oder minder hinter
> > einem Feigenblatt verborgen wird.
>
> *Das* weiss ich selbst.

Warum fragst Du dann? Du weißt sicher auch, daß die meisten
Kontrollstrukturen prinzipiell redundant sind und der Bequemlichkeit/
Übersichtlichkeit halber verwendet werden.

----------------------
p = pacct->gr_mem;
while (1) {
if (!*p) break;
if (strcmp(*p, user->pw_name) == 0) {
if (argv[1]) log_access(user->pw_name, argv + 1, argc - 1);
goto found;
}

++p;
}

setuid(uid);
}

found:
execve(COMMAND, argv, env);
perror("execve");
----------------------

Für goto gilt das desgleichen.

> > Obiges gilt entsprechend: Objekte im RAM haben eine Adresse, die die
> > CPU benutzt, um sie zu adressieren.
>
> Und? Deswegen muss ich das Objekt auf Source-Ebene nicht mit seiner
> Adresse ansprechen.
>
> Da kannst Du auch gleich wieder Assembler programmieren.

Das Gegenteil von A ist !A und nicht B. Es bringt nichts, die Adressen
wegzuabstrahieren, also wozu tun?

> >> Was ich mit SHOLIS meinte: Wenn mit SPARK ein System beschreiben
> >> kann, welches die sicherheitskritische Software eines Helikopters
> >> darstellt,
> >
> > Es ist «bewiesen», daß man so ein System in Visual Basic beschreiben
> > kann.
>
> So, kann man das?

Ja und zwar wegen 'turing vollständig'.

Stefan Nobis

unread,
Jan 28, 2003, 1:05:49 PM1/28/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> Das «Verständnis» sagt per se gar nichts aus. Aber der Quelltext tut
> das: Er ist eine vollständige Beschreibung dessen, was die Software zur
> Laufzeit tun wird.

Davon träumst du, oder?

Dein Programm nutzt Bibliotheksfunktionen, greift auf Syscalls zurück,
läuft auf komplexen ICs usw. Und in derart umfangreichen und komplexen
Systemen hälst du einen Quelltext für eine *vollständige* Beschreibung
dess, was das Programm zur Laufzeit (also der durch das compilierte
Programm im Prinzip beschriebene Task) tut?

Aberwitziger Unsinn!

> dem Programmierer überlassen. Falls man dem vorher nicht zutrauen
> konnte, faktisch korrekten Code zu schreiben (insofern möglich), warum
> sollte er es hinterher plötzlich können?

Wenn es um kritische Systeme geht, kann man getrost davon ausgehen,
dass *kein* einziger Mensch jemals korrekten, sprich 100%
fehlerfreien, Code schreibt.

Ziel muss es also sein, einerseits Fehler verstärkt zu vermeiden und
es gibt Möglichkeiten, die (durchschnittliche) Fehlerquote beim
Programmieren mit diversen Mitteln zu reduzieren. Andererseits
versucht man möglichst automatisiert Fehler zu finden -- dazu ist
natürlich ein Mindestmaß an Redundanz notwendig (dies beruht auf der
Annahme, dass in hinreichend unterschiedlichen Beschreibungssystemen
Menschen nicht dieselben Detailfehler machen -- die Erfahrung legt
nahe, dass dies stimmt; wie gesagt Detailfehler; grundlegendere
(logische) Fehler wird man so sicher kaum finden, dafür hat man dann
die Leute, die grundlegende Elemente/Algorithmen des Systems auf
Korrektheit prüfen und diese auch Beweisen -- und dies durch
Peer-Review kontrollieren lassen).

> Wegen einer formalen Beschreibung ohne Fehler
> bekomme ich keinen Quelltext ohne Fehler, und (zum 1000x):

Natürlich nicht.

> Ein Programm ist bereits eine formale Beschreibung.

Aber auf einem völlig anderen Abstraktionsniveau. Auf diese Weise
bekomme ich etliche neue Fehlerquellen.

Wenn nun die nicht-quelltext Spezifikation auf höherem
Abstraktionsniveau nachgewiesen fehlerfrei ist/wäre, so muss ich im
Quelltext nur noch auf unterster Ebene nach Detailfehlern bei der
Umsetzung suchen und nicht mehr auf jeder Ebene auf Fehler achten.

Dies wirkt sich auch auf verschiedene Weise aus: Ein Peer-Review ist
evtl. auf breiterer Basis möglich, abstraktere Konzepte und Module
lassen sich (bei evtl. unterschiedlicher Implementation) leichter
wiederverwenden, durch verschiedene Ausdrucksformen fallen
evtl. eher/mehr Fehler auf etc.

> > Eine Registermaschine ist auch turing-vollstaendig. Warum also C?

> C-Programme beschreiben normalerweise Registermaschinen.

So ein Quark. C basiert noch nicht einmal auf einer klaren
Maschinenbeschreibung (wie z.B. Lisp) und noch viel weniger
beschreiben C Programme eine Registermaschine (welchen Sinn sollte das
auch machen) -- du selbst hast doch gesagt, Quelltext beschreiben, was
zur Laufzeit passiert. Wie sollen sie außerdem auch noch Maschinen
beschreiben?

[Spielzeugsprache]


> ZB eine ohne dynamische Speicherverwaltung und ohne
> Rekursionen. Insbesondere letzteres mutet abstrus an, denn gerade
> rekursive Algorithmen kann man oft einfach durch Induktion beweisen.

[...]


> Wie bereits erwähnt: Ich möchte nicht mein Leben einem Programm von
> jemandem anvertrauen, dem es «kompliziert» erscheint,
> integer-Überläufe im Quelltext sinnvoll zu behandeln und der ein
> Spezialtool braucht, um potentielle zu finden. Dazu gibt es zuviele
> esoterische Fehlermöglichkeiten.

Und eben weil es viele esoterische Fehlermöglichkeiten gibt, sollte
man alle Möglichkeiten, Fehler zu vermeiden, nutzen. Wieso nicht
gleich eine Sprache, bei der etliche Fehlerklassen (z.B. wilde Zeiger)
schlicht unmöglich sind?

Wieso sind einige Abstraktionskonzepte, wie Rekursionen u.a., wichtig
und gut und andere wieder völlig überflüssig und böse?

> > > Obiges gilt entsprechend: Objekte im RAM haben eine Adresse, die die
> > > CPU benutzt, um sie zu adressieren.

> > Und? Deswegen muss ich das Objekt auf Source-Ebene nicht mit seiner
> > Adresse ansprechen.

> > Da kannst Du auch gleich wieder Assembler programmieren.

> Das Gegenteil von A ist !A und nicht B. Es bringt nichts, die Adressen
> wegzuabstrahieren, also wozu tun?

Um Fehlerquellen zu vermeiden. Mit Adressen, zumal ihrer
Repräsentation(!) in C, kann man rechnen, mit Referenzen (einer
anderen Repräsentation) kann man nicht rechnen -- damit sind wilde
Zeiger z.B. (nahezu) unmöglich. Eine komplette Klasse von Fehler
ausgemerzt. Und das ist jetzt noch mal aus welchem Grund schlecht?

--
Stefan.

Rainer Weikusat

unread,
Jan 28, 2003, 1:01:59 PM1/28/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Rainer Weikusat wrote:
> > Stefan Nobis <ste...@snobis.de> writes:
> >> Ist C also bloatig? Nein? Wo genau ist dann die Grenze von sinnvollen
> >> Abstraktionen?
> >
> > Es ging um notwendige Abstraktionen.
>
> Wo genau ist die Grenze zwischen sinnvoll und notwendig?

Falls ich concurrency brauche (oder auch nur benutzen möchte), brauche
ich notwendigerweise einen Mechanismus dafür. Sowohl C als auch Ada
bieten das und in beiden Fällen ist es Bestandteil des
Laufzeitsystems, falls vorhanden: In Ada deswegen, weil eine konkrete
Semantik vorgeschrieben ist, in C, weil keine konkrete Semantik
verboten wird.

> >> It depends? Ah, und warum dann nicht Sprachen verwenden, die mehr
> >> Abstraktionsmittel als C zur Verfügung stellen (sofern man sie
> >> benötigt!)?
> >
> > Weil einem diese Dinge real auch ohne spezifischen language support
> > zur Verfügung stehen.
>
> Und alle Sprachen, die mehr Features als C zur Verfuegung stellen, sind
> demzufolge Spielzeugsprachen? Ich kann Dir nicht ganz folgen,

Dann solltest Du etwas mehr auf meine Worte hören, anstatt meine
wahrscheinlichen Gedanken zu erraten versuchen.

> aber
> bitte:
>
> |function Get_Speed (Distance : in Meter;
> | Time : in Seconds) return Speed;
>
> Natuerlich *kann* man in C selbst darauf achten, dass man die Funktion
> immer mit den richtigen Parametern aufruft und dass der Aufruf dieser
> Funktion keine Seiteneffekte hat.

Man kann auch stattdessen einen vernünftigen Entwurf machen:

double get_speed(double distance)¹
{
static double last_distance = -1;
static uint32_t last_time = 0;

Alternativ

struct dist_info {
uint32_t last_time;
double last_pos;
};

double get_speed(struct dist_info *info, double distance)

1) Ein Subsystem ist äquivalent zu einem Objekt, von dem es genau eine
Instanz gibt. Aus dem Umkehrschluß folgt außerdem, das
hemmungsloser Gebrauch globaler Variablen immer noch sehr populär
ist.

> Aber warum sollte ich das auch noch muessen? Ich habe durchaus besseres
> zu tun.

Wolltest Du jetzt damit andeuten, Du hättest durchaus besseres zu tun,
als semantisch richtigen Code zu schreiben, oder eher, es würde Dich
übermäßig viel Mühe kosten, die Reihenfolge zweier Parameter zu
behalten oder zu korrigieren? :->

Ich wage die Behauptung, daß überkomplexe (also -generalisierte :->)
Interfaces für mehr Fehler verantwortlich sind, als integer-Überläufe,
sowie, daß diese Fehler außerdem schwerer zu finden sind. Das
Zwei-Parameer-Beispiel ist natürlich etwas konstruiert, aber tools,
die schlechte Entwürfe einfacher handhabbar machen, halte ich nicht
für notwendig.

Vinzent Hoefler

unread,
Jan 28, 2003, 1:47:44 PM1/28/03
to
Rainer Weikusat wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Rainer Weikusat wrote:
>> > Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> >> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
>
>> >> Wenn ich das jetzt mal frei interpretiere, akzeptierst Du damit
>> >> den Tod von Menschen als aergerlich, aber tolerabel,
>> >
>> > Lieber Vinzent, ich glaube, ich lege Maßstäbe an Software an, die
>> > Du Dir noch nicht einmal vorstellen kannst.
>>
>> Ehrlich gesagt, das *will* ich mir auch gar nicht vorstellen.
>
> Dann bleibt zu hoffen, daß Dich jemand aus dem Verkehr zieht, bevor Du
> wegen gemeingefährlicher Lernresistenz ein paar Menschen auf dem
> Gewissen hast.

Eher andersrum.

> Tut mir leid, aber das ist definitiv nicht mehr komisch.

Eben. Aber Deinen Aussagen nach zu urteilen, die darauf schliessen
lassen, dass Du ausschliesslich dem "faehigen Programmierer" vertraust,
koennen Deine Massstaebe an Software nicht allzu hoch sein.

>> Das Verstaendnis des Quellcodes sagt nichts ueber seine Korrektheit
>> aus.
>
> Das «Verständnis» sagt per se gar nichts aus. Aber der Quelltext tut
> das: Er ist eine vollständige Beschreibung dessen, was die Software
> zur Laufzeit tun wird.

Nein, diese Beschreibung ist mitnichten vollstaendig. Was tut das
System, wenn die Software einen Zeiger dereferenziert, der auf ein
zufaellig bereits freigegebenes Objekt zeigt? Was passiert, wenn mit
den Ergebnissen aus uninitialisierten Variablen gerechnet wird? Das
ganze ist nicht einmal mehr deterministisch, was willst Du da mit dem
Source anfangen?

Und *Du* kannst bei 100KSLOC *garantieren*, dass keiner dieser Fehler
auftritt?

>> Und es wohl kaum moeglich, ein 100'000 Zeilen-Programm vollstaendig
>> zu verstehen und garantieren zu koennen, dass es das tut, was es tun
>> soll, unter allen Umstaenden.
>
> Es ist möglich, eine 100.000-Zeilen-Programm so zu konstruieren, daß
> man keine Einheiten von mehr als maximal tausend Zeilen hat und so,
> daß diese Einheiten keine internen Abhängigkeiten haben.

Ja. Was nicht heisst, dass es nachher funktioniert.

> Die Grundvoraussetung für das, was ich geschrieben hatte
> («Tolerabilität von fringe case-Fehlersituationen»), ist, daß das
> System deswegen nicht Amok läuft, was man durch einen geeigneten
> internen Aufbau sicherstellt.

Und in SPARK durch den Beweis der Abwesenheit von Laufzeitfehlern
garantieren kann.

> Wenn das für Dich nicht selbstverständlich ist,

Das ist fuer mich durchaus selbstverstaendlich. Was fuer mich nicht
selbstverstaendlich ist, wie das in irgendeiner Weise korrekte Software
garantieren soll.

> und diesen Eindruck erweckst Du gerade, bist
> Du eine Gefahr für Deine Umgebung,

Das bezweifle ich.

> deren Umfang ausschließlich von dem
> Gefahrenpotential dessen, womit man Dich herumspielen läßt,

:-)

>> It is easier to fit the specification to a program than vice versa?
>
> Entweder das Programm ist eine Übersetzung der Spezifikation in eine
> andere Sprache oder Du hast einen schrecklichen Fehler gemacht, der
> sich auch mit 400t glue code im Nachhinein nicht mehr wird
> reparieren lassen.

Sorry, entweder Du traeumst oder Du bist einer von denen, die immer auf
Anhieb korrekte, der Spezifikation entsprechende Software schreiben
koennen. Wieviele Fehler hast Du im Durchschnitt pro Tausend Zeilen
Code?

BTW, auch die Spezifikation kann falsch sein bzw. Inkonsistenzen haben.
Beim MultOS-CA hat man 38 Fehler aus der Spezifikationsphase erst in
der Kodierphase gefunden und einen waehrend der Operation.

>> Und Leute, die sich ein klein wenig mit diesen Methoden beschaeftigt
>> haben, wissen, dass die SPARK-Annotations nicht den ausfuehrenden
>> Code darstellen. Ja, es ist redundant, nachdem der Examiner
>> festgestellt hat, dass beides korreliert.
>
> Lediglich wird von dem nicht erwartet, tatsächlich alle Fehler zu
> finden, sondern bloß alle möglichen Fehler.

Richtig.

> Der Rest wird dann wieder dem Programmierer überlassen.

Natuerlich.

> Falls man dem vorher nicht zutrauen
> konnte, faktisch korrekten Code zu schreiben (insofern möglich), warum
> sollte er es hinterher plötzlich können?

Weil Menschen Fehler machen. Aber das solltest Du wissen.

>> Du stimmst mir also zu, dass Fehler im Quellcode wesentlich schwerer
>> zu finden sind als im Zuge einer formalen Beschreibung?
>
> Wie käme ich denn dazu? Wegen einer formalen Beschreibung ohne Fehler
> bekomme ich keinen Quelltext ohne Fehler,

In SPARK hast Du sehr gute Chancen dazu.

> und (zum 1000x): Ein Programm ist bereits eine formale Beschreibung.

LOL

Ein formale Beschreibung, deren Konsistenz Du bitte *wie* nachweist?
Durch Code-Reviews durch andere Programmierer, die Du hier
offensichtlich als unfaehig hinstellst?

>> >> "Ein Programm mit mehr als fünfhundert Zeilen besteht aus sauber
>> >> getrennten Subsystemen/ Modulen, die ausschließlich über
>> >> definierte Interfaces kommunizieren und deren Interna unterhalb
>> >> einer prozeduralen Spezifiaktion des Interfaces lokalisiert
>> >> bleiben und jeder einzelne dieser Teile ist klein genug, damit man
>> >> ihn separat debuggen kann."
>> >> (<87n0lxjr...@winter.inter-i.wohnheim.uni-mainz.de>)
>> >>
>> >> So die Theorie und in den vielen Faellen mag das stimmen. Laut Rod
>> >> (und ich glaube da einfach mal seiner Erfahrung) findet man die
>> >> meisten Fehler aber, wenn man diese einzelnen Unit zusammenfuegen
>> >> will, also letztendlich im Interface. Das ist im uebrigen auch
>> >> meine Erfahrung.
>> >
>> > Das ist eine groteskte Horrortheorie,
>>
>> Diese Theorie stammt von Dir, danke.
>
> Warum sollte ich mich denn vollkommen widersinnig auf meinen Text
> beziehen anstelle auf Deinen?

Weil ich auf Deinen Text bezogen "So die Theorie" schrieb.

>> Oder meintest Du eher:
>>
>> IEEE Software Vol. 19, No. 1, Jan/Feb 2002:
>>
>> "Traditionally critical-systems testings is very expensive. A reason
>> for this is that testing occurs several times: we test indivisual
>> units, integrate them and test the integration, and then the system
>> as whole. Our experience with previous safety-critical projects
>> suggests that this approach is inefficient and particularly that unit
>> testing is ineffective because most errors are interface errors, not
>> internal errors in units.
>
> Bei allen Dingen, mit denen ich praktisch zu tun habe, und dazu gehört
> Quellcode anderer Leute mit dazu, verhält sich das genau umgekehrt, dh
> der Code tut nicht das, was das Interface angeblich bereitstellt.

Dann solltest Du die Leute grundsaetzlich wegen Unfaehigkeit feuern.
Oder was genau ware es noch mal, was Du oben aussagen wolltest?
Unfaehige Programmierer?

>> > deren Implikationen ausschließlich besagen, daß die Resultate
>> > lebensgefährlich sein werden.
>>
>> Interessant. Wie kommst Du darauf?
>
> Ich denke nicht, daß ich das Dir in einem Usenet-angemessenen Rahmen
> erklären kann, aber jedenfalls würde ich nie so wahnsinnig sein, mein
> Leben einem Computerprogramm anzuvertrauen, auf das diese Aussage
> zutrifft, falls ich nicht ohnehin Hazard spiele.

Irgendwie habe ich jetzt was nicht ganz begriffen. Die Nutzung formaler
Verifikationstechniken impliziert Lebensgefaehrlichkeit des Produkts?
Oder meintest Du, wenn die Lebensgefaehrlichkeit des Produkts durch
formale Methoden bewiesen ist?

Ansonsten, steige bitte nie wieder in ein Flugzeug, vor allem nie weider
in eine Boeing. Das ist lebensgefaehrlich. Die Software haben nicht nur
unfaehige Idioten geschrieben, die zu bloed sind, Integer-Ueberlaeufe
schon im Source zu erkennen, sondern diese Software ist auch noch
zertifiziert.

>> Ich bin immer noch nicht ganz dahintergekommen, was Du mit
>> Spielzeugsprache meinst.
>
> ZB eine ohne dynamische Speicherverwaltung

Brauche ich wirklich selten. Und in Embedded Systems- bzw.
Safety-Critical-Umgebungen will man das auch nicht. Es wird Dir in den
seltensten Faellen gelingen, nachzuweisen, dass Deine Techniken nicht
zu Speicherfragmentierung und/oder Memory-Leaks fuehren.

> und ohne Rekursionen.

Der SPARK-Examiner selbst ist in SPARK geschrieben. Und ja, der Parser
ist statisch verifiziert und benutzt weder Rekursion noch dynamischen
Speicher. Rod war natuerlich durchaus der Meinung, dass das nicht sehr
einfach war.

> Insbesondere letzteres mutet abstrus an, denn gerade
> rekursive Algorithmen kann man oft einfach durch Induktion beweisen.

Auch deren Stackverbrauch, bevor die Runtime-Umgebung ein Storage_Error
ausloest (oder halt nicht)?

>> Eine Sprache, die es einfacher macht, korrekten Code zu schreiben,
>> weil das dann ja jedes Kind tun kann?
>
> Wie bereits erwähnt: Ich möchte nicht mein Leben einem Programm von
> jemandem anvertrauen, dem es «kompliziert» erscheint,
> integer-Überläufe im Quelltext sinnvoll zu behandeln

Falls Du das auf mich beziehst: Beispiele sind naturgemaess stark
vereinfacht.

> und der ein
> Spezialtool braucht, um potentielle zu finden.

Wenn Du das so meinst. Demzufolge sollten sicherheitskritische Programme
in moeglichst schwierigen, unsicheren Sprachen geschrieben werden,
damit da auch ja nur die absolut fehlerfrei arbeitende Elite daran
arbeitet?

Oder was wolltest Du sagen?

> Dazu gibt es zuviele esoterische Fehlermöglichkeiten.

Eben diese versucht das Tool zu finden, indem es *alle* Moeglichkeiten
durchgeht. Ein gegebenes Register hat nur eine endliche Zahl von
Bitmustern.

>> Dein Problem, ich schreibe keine Software, um mit Compiler und
>> Debugger zu kaempfen, ich schreibe Software, um etwas zum Laufen zu
>> bekommen.
>
> Vermutlich wäre «davonlaufen» anzuraten.

Kaum. Das interessante ist, dass es in der Mehrzahl der Faelle zum
Run-Once-Never-Touch-Again-Syndrom kommt. Debugger brauche ich sehr
selten.

>> >> Das einzige, was Dir fehlt, sind gotos (braucht
>> >> man die?)
>> >
>> > «Man» benutzt sie ständig, was vom Compiler mehr oder minder hinter
>> > einem Feigenblatt verborgen wird.
>>
>> *Das* weiss ich selbst.
>
> Warum fragst Du dann?

Weil es eine Frage nach den expliziten gotos war, nicht nach
irgendwelchen Kontrollstrukturen.

> Du weißt sicher auch, daß die meisten
> Kontrollstrukturen prinzipiell redundant sind und der Bequemlichkeit/
> Übersichtlichkeit halber verwendet werden.

Ja.

> ----------------------
> p = pacct->gr_mem;
> while (1) {
> if (!*p) break;
> if (strcmp(*p, user->pw_name) == 0) {
> if (argv[1]) log_access(user->pw_name, argv +
> 1, argc - 1); goto found;
> }
>
> ++p;
> }
>
> setuid(uid);
> }
>
> found:
> execve(COMMAND, argv, env);
> perror("execve");
> ----------------------

Warum nicht so (den Rest nach dem goto-Label spare ich mir mal),
ungefaehr zumindest:

for i in P'Range loop
if (P (i) = NULL) then
Set_UID (uid);
exit;
end if;

if (P (i) = User.PW_Name) then
if (Argument (1) /= "") then
Log_Access (User.PW_Name, Argument (1), Argument_Count);
exit;
end if;
end if;
end loop;

Die zwei Exits sind etwas unschoen, aber ich denke, ich habe sowohl Dein
break als auch Dein goto ordentlich umgesetzt. Schlimmer sieht es
jedenfalls erst einmal auch nicht aus. Habe ich was uebersehen?

Zugegeben, zu den Parametern zu Log_Access gibt es keine direkte
Entsprechung, da Argument () halt eine einen String zurueckliefernde
Funktion ist und nicht irgendeine Adresse auf irgendwelchen Speicher,
der zufaelligerweise die Kommandozeile beinhaltet.

> Für goto gilt das desgleichen.

Ja. Wer hatte das gleich noch mal bewiesen, als die goto-befuerworter
das anzweifelten?

> Das Gegenteil von A ist !A und nicht B. Es bringt nichts, die Adressen
> wegzuabstrahieren,

Aber sicher bringt das etwas.

> also wozu tun?

Deswegen:

|void something (char* blabla)

vs.

|procedure Something (BlaBla : in Char_Array);

vs

|procedure Something (Blabla : out Char_Array);

Jetzt versuche mal, den drei Funktionen eine Nullzeiger zu uebergeben
und bei der C-Variante zu erzaehlen, ob blabla veraendert wird.

Manchmal sind Abstraktionen der bessere Weg.


Vinzent.

--
The world is an 8000 mile in diameter spherical pile of shit.

Vinzent Hoefler

unread,
Jan 28, 2003, 2:20:09 PM1/28/03
to
Rainer Weikusat wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Rainer Weikusat wrote:
>> > Stefan Nobis <ste...@snobis.de> writes:
>> >> Ist C also bloatig? Nein? Wo genau ist dann die Grenze von
>> >> sinnvollen Abstraktionen?
>> >
>> > Es ging um notwendige Abstraktionen.
>>
>> Wo genau ist die Grenze zwischen sinnvoll und notwendig?
>
> Falls ich concurrency brauche (oder auch nur benutzen möchte), brauche
> ich notwendigerweise einen Mechanismus dafür.

Allein das Typ- oder Parameteruebergabekonzept ist eine Abstraktion. Und
*die* hilft.

> Sowohl C als auch Ada
> bieten das und in beiden Fällen ist es Bestandteil des
> Laufzeitsystems, falls vorhanden: In Ada deswegen, weil eine konkrete
> Semantik vorgeschrieben ist, in C, weil keine konkrete Semantik
> verboten wird.

Was Dir dazu verhilft, dass Du je nach Zielsystem eine andere Semantik
geboten bekommst.

>> aber
>> bitte:
>>
>> |function Get_Speed (Distance : in Meter;
>> | Time : in Seconds) return Speed;
>>
>> Natuerlich *kann* man in C selbst darauf achten, dass man die
>> Funktion immer mit den richtigen Parametern aufruft und dass der
>> Aufruf dieser Funktion keine Seiteneffekte hat.
>
> Man kann auch stattdessen einen vernünftigen Entwurf machen:
>
> double get_speed(double distance)¹
> {
> static double last_distance = -1;
> static uint32_t last_time = 0;

Vernuenftig, wenn man nur noch mit einer globalen Zeit arbeitet? Sorry.
Null Punkte.

> Alternativ
>
> struct dist_info {
> uint32_t last_time;
> double last_pos;
> };
>
> double get_speed(struct dist_info *info, double distance)

Besser, aber benoetigt hier schon wieder unsinnigerweise den Einsatz von
Zeigern und in diesem Fall sagt mir das auch Interface nicht, ob
dist_info nicht evt. veraendert werden koennte. Und das Ergebnis von
get_speed kann immer noch einer distance-Variablen zugewiesen werden.

Ehrlich, warum soll ich mir so etwas auf Dauer antun, wenn ich das in
anderen Sprachen viel einfacher und zum Nulltarif haben kann?

> 1) Ein Subsystem ist äquivalent zu einem Objekt, von dem es genau eine
> Instanz gibt. Aus dem Umkehrschluß folgt außerdem, das
> hemmungsloser Gebrauch globaler Variablen immer noch sehr populär
> ist.

Globale Variablen sind boese. Ja, das ist zu pauschal, ich weiss.

> Wolltest Du jetzt damit andeuten, Du hättest durchaus besseres zu tun,
> als semantisch richtigen Code zu schreiben,

Nein, denn genau darum geht es mir. Ich moechte semantisch korrekten
Code schreiben. Und wenn mich der Compiler auf Tippfehler oder
meinetwegen auch logische Fehler, die immer mal wieder passieren,
hinweist, steigert das meine Produktivitaet, weil ich den Fehler dann
nicht erst Tage spaeter nach drei Naechten debugging finde.

Aber Dir ist sicher noch nie an der falschen Stelle ein Semikolon
abhanden gekommen, oder?

> oder eher, es würde Dich
> übermäßig viel Mühe kosten, die Reihenfolge zweier Parameter zu
> behalten oder zu korrigieren? :->

Tja, *ich* verwechsle z.B. nach wie vor die Parameter bei memcpy (). Ich
kann mir das einfach nicht abgewoehnen. Und ja, es ist tatsaechlich
ziemlich viel Muehe, sich von einem Projekt zum anderen immer die
Reihenfolge irgendwelcher Parameter von Funktionen zu merken, die
andere geschrieben haben. Zumal wenn diese anderen dieses Interface
gelegentlich aendern.

> Ich wage die Behauptung, daß überkomplexe (also -generalisierte :->)
> Interfaces für mehr Fehler verantwortlich sind, als integer-Überläufe,
> sowie, daß diese Fehler außerdem schwerer zu finden sind.

Njet. In C bemerkt man die Ueberlaeufe halt nicht. Und es macht ja auch
nichts, mal fix im Array einen daneben zu greifen, wenn es nicht gerade
segfaultet.

> Das
> Zwei-Parameer-Beispiel ist natürlich etwas konstruiert,

Ok, anderes:

|Mem_Copy (Src => From_This;
| Dest => To_That;)

Da muss ich mir gar keine Gedanken mehr machen. Dort weiss, *dass* es
korrekt ist, ohne in die Deklaration schauen zu muessen.

> aber tools,
> die schlechte Entwürfe einfacher handhabbar machen, halte ich nicht
> für notwendig.

Ganz im Gegenteil. SPARK fordert sogar einen sehr guten Entwurf, weil
sonst der Bedarf an generierten VCs exponentiell ansteigt und Du ewig
und drei Tage auf Deinen Beweis warten kannst.


Vinzent.

Rainer Weikusat

unread,
Jan 28, 2003, 4:28:50 PM1/28/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Rainer Weikusat wrote:
> > Sowohl C als auch Ada bieten das und in beiden Fällen ist es
> > Bestandteil des Laufzeitsystems, falls vorhanden: In Ada deswegen,
> > weil eine konkrete Semantik vorgeschrieben ist, in C, weil keine
> > konkrete Semantik verboten wird.
>
> Was Dir dazu verhilft, dass Du je nach Zielsystem eine andere Semantik
> geboten bekommst.

Ja.

> >> aber
> >> bitte:
> >>
> >> |function Get_Speed (Distance : in Meter;
> >> | Time : in Seconds) return Speed;
> >>
> >> Natuerlich *kann* man in C selbst darauf achten, dass man die
> >> Funktion immer mit den richtigen Parametern aufruft und dass der
> >> Aufruf dieser Funktion keine Seiteneffekte hat.
> >
> > Man kann auch stattdessen einen vernünftigen Entwurf machen:
> >
> > double get_speed(double distance)¹
> > {
> > static double last_distance = -1;
> > static uint32_t last_time = 0;
>
> Vernuenftig, wenn man nur noch mit einer globalen Zeit arbeitet?

Das kommt darauf an, wofür man die verwendet.

> > Alternativ
> >
> > struct dist_info {
> > uint32_t last_time;
> > double last_pos;
> > };
> >
> > double get_speed(struct dist_info *info, double distance)
>
> Besser, aber benoetigt hier schon wieder unsinnigerweise den Einsatz von
> Zeigern

s/un//

> Aber Dir ist sicher noch nie an der falschen Stelle ein Semikolon
> abhanden gekommen, oder?
>
> > oder eher, es würde Dich
> > übermäßig viel Mühe kosten, die Reihenfolge zweier Parameter zu
> > behalten oder zu korrigieren? :->
>
> Tja, *ich* verwechsle z.B. nach wie vor die Parameter bei memcpy ().

Simpel: Andersherum.

Vinzent Hoefler

unread,
Jan 28, 2003, 4:41:51 PM1/28/03
to
Rainer Weikusat wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Rainer Weikusat wrote:
>>
>> > double get_speed(double distance)¹
>> > {
>> > static double last_distance = -1;
>> > static uint32_t last_time = 0;
>>
>> Vernuenftig, wenn man nur noch mit einer globalen Zeit arbeitet?
>
> Das kommt darauf an, wofür man die verwendet.

Sicher. Allerdings entzieht sich meinem Verstaendnis, inwieweit Du hier
eine globale Zeit voraussetzt. Wenn ich das getan haette, hiesse die
Funktion get_current_speed (). :-)

Ohnehin sind Funktionen in SPARK aber seiteneffektfrei. Das waere sie
hier nicht. Wobei das in Hinblick auf C ohnehin eine eher theoretische
Betrachtung ist, weil es die Unterscheidung zwischen Funktion, die
einen Wert zurueckliefert und einer Prozedur, die den Zustand des
Systems aendert, ohnehin nicht wirklich gibt.

>> > Alternativ
>> >
>> > struct dist_info {
>> > uint32_t last_time;
>> > double last_pos;
>> > };
>> >
>> > double get_speed(struct dist_info *info, double distance)
>>
>> Besser, aber benoetigt hier schon wieder unsinnigerweise den Einsatz
>> von Zeigern
>
> s/un//

Nein, dies ist lediglich bedingt durch die Einschraenkung von C, welches
keine Parametermodi kennt. Insofern ist es zwar notwendig, aber
keineswegs sinnvoll.

>> Tja, *ich* verwechsle z.B. nach wie vor die Parameter bei memcpy ().
>
> Simpel: Andersherum.

Und dann habe ich wieder das gleiche Problem. War es nun andersherum
oder nicht?

Aus dem Kopf: 1: source, 2: dest, oder?

Und ja, das ist fehleranfaellig. Schliesslich geht es nicht nur um
memcpy.


Vinzent.

--
All a hacker needs is a tight PUSHJ, a loose pair of UUOs, and a warm
place to shift.

Georg Bauhaus

unread,
Jan 28, 2003, 7:27:13 PM1/28/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
: denn daf?r ist sie da. Ich mu? allerdings gestehen, Dir nicht ganz
: folgen zu k?nnen.

Ich wollte andeuten, dass es nicht mehr einfach ist, die Bedeutung
einer Hochsparchen-Operation im Detail pruefen oder vorher sagen
zu koennen:
In einem nebenlaeufigen Programm sei '=' im Quellcode angetroffen.
Was genau, im hinblick auf die betroffenen Daten (lhs, rhs),
im Hinblick auf die betroffenen Programm-Teile,
im HInblick auf die Stack-Nutzung,
im Hinblick auf die heap-Nutzung,
im Hinblick auf die waehrend '=' ablaufenden clock ticks,
bedeutet '='?
Faellt es dir hier so leicht, sagen wir innerhalb von 2 min,
diese Angaben fuer einen Echtwelt-Wartungsfall zu machen?

Waere es so falsch, ein tool ein zu setzen, dass ermoeglicht,
einem '=' Beschraenkungen auf zu erlegen, die solche Fragen
leichter und zuverlaessiger zu beantworten erlaubt?

:> Jedes turing-vollstaendige setup koennte Speichersammlung


:> bereitstellen. Wer/was schuetzt die Steuerung des Roentgen-Kastens
:> davor, dass das jemand versehentlich genutzt hat?

: Wovon sprichst Du?

EIn Roentgen-Geraet hat eine Bestrahlungs-Dauer die nicht ueberschritten
werden darf. Sollte in einem Programm garbage collection erlaubt
sein kann dabei Zeit drauf gehen, vielleicht im falschen Moment: der
Bestrahlung. Wenn doch ein tool solchen sonst sinnvollen Sprachgebrauch
an dieser Stelle verhindern hilft, was ist dagegen ein zu wenden?


:> Sicher, aber "compiler" != "man".



: Der Compiler tut aber nichts von alleine.

In der Tat, und er hat eine Menge Pruefroutinen eingebaut,
die waehrend der Uebersetzung Fehler finden helfen. Das muessen
nicht nur die gerade so eben notwendigen sein, die die jeweilige
Sprach-Definition verletzen, sondern das koennen ergaenzende sein,
wie im Fall von lclint (splint). Es ist wohl auch Moeglich, einen
"prover" in diese Kategorie zum Teil ein zu ordnen?

:> Die Behauptungen, die in einem Programm-Quelltext enthalten sind,


:> koennen glaube ich ohne Gesichtsverlust explizit gemacht werden,

: Sie sind es bereits.

Kommt drauf an. Wenn irgendwo long in einem C Programm steht,
ist damit noch nicht gesagt, welche Teilmenge von Zahlen in der
entsprechenden Groesse enthalten sein werden.


: Wenn Du den Quellcode ver?ndern m?chtest, mu?t Du


: den vorher gelesen und verstanden haben.

Wie Alan Turing vorgeschlagen hat, bei groesseren Programmen
helfen Zwischen-Betrachtungen des Bandes und der Zustaende (Beweis:
Begrenztheit menschlichen Denkens). Auch haben wir nicht ohne
Grund Hochsprachen und Inferenzmaschinen. Was spricht gegen eine
Sprache, die es einem tool erlaubt, ueber Algorithmen, die in der Sprache
formuliert sind, korrekte Aussagen zu machen, die ueber die uebliche
compiler-Pruefung hinaus gehen?

(Assertions als Beispiel zur Explizitheit des semantischen
Inhalts eines Programms: Sie sind in einigen Sprachen
mehr, in anderen weniger explizit angebbar. Es sei denn du findest
es vorteilhaft, wenn die Programmierer, sagen wir die von dir
genannten "Engineers", diese Pruefungs-Anweisungen und deren Handling
repetitiv und explizit selbst schreiben, Mechanismen, die sonst in
Sprachen enthalten sind.)

Gruesse, Georg

Georg Bauhaus

unread,
Jan 28, 2003, 7:59:52 PM1/28/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

: ZB eine ohne dynamische Speicherverwaltung und ohne

: Rekursionen. Insbesondere letzteres mutet abstrus an, denn gerade
: rekursive Algorithmen kann man oft einfach durch Induktion beweisen.

Daran kein Zweifel. Aber, und da glaube ich scheint ein
entscheidendes Misverstaendnis vor zu liegen, es geht bei SPARK
zunaechst um Systeme, bei denen Speicher fuer heutige Verhaeltnisse
abstrus knapp sein kann. So knapp, dass Rekursion (direkte und
indirekte) deswegen (implizit) nicht zugelassen ist, weil im
allgemeinen Fall fuer den Funktions-Aufruf stack-speicher, und
zwar in statisch nicht vorhersagbarer Menge, benoetigt werden wird.
Das ist hier entscheidend.
Es geht u.a. um statische Vorhersagbarkeit des verbrauchten
stack-Speichers: Es muss sicher gestellt sein, dass das Programm,
so wie du auch gefordert hast, nicht an die Decke knallt, sozusagen,
Oder amok laeuft, sondern sich faengt, vorhersagbar verhaelt,
und dafuer muss im allgemeinen Fall Speicher da sein.

Beispiel: Die Steuerung einer automatischen Tuer hat in einem
aussergewohlichen (tolerablen?) Fall jemanden eingeklemmt. Wenn
- ich Rekursion im Steuerprogramm nach belieben erlaube, und
- Funktionen Seiteneffekte zB auf elektrisches Geraet haben duerfen,

dann kaenn es sein, dass kein stack-speicher da ist, um reset-Routinen
aufzurufen. Ich koennte verlangen, dass dann stack speicher fuer
solche Faelle reserviert ist, aber wieviel, wenn rekursion etc
zugelassen ist? Ich koennte verlangen, dass der Aufrufstapel einfach
abgeraeumt wird, aber habe ich dann noch hinreichend Information
ueber der Zustand von Variablen, die den Zustand externer GEraete
aufgezeichnet haben? Alles in statisch reservierten Variablen
speichern?

Auswege sind offenbar nicht immer leicht zu finden, und ohne
Zweifel ist ein geeigneter System-Entwurf unentbehrlich. Aber
ich weiss immer noch nicht, was gegen den Einsatz eines tools
spricht, dass eine Sprache verarbeitet, die mir beim Umsetzen
eines Entwurfs nach Implementations-Richtlinien "auf die Finger
schaut". Ich denke, es gibt nicht viele Leute, die so gut sind
wie sozusagen ein compiler, runtime-experte, Korrektheits-Pruefer
und "O(f(n))-Beweiser" in einer Person.

Ist zB lint (lclint, splint) ein ebenso verwerfliches Werkzeug?

Gruesse,
Georg


:> Eine Sprache, die es einfacher macht, korrekten Code zu schreiben,


:> weil das dann ja jedes Kind tun kann?
:

: Wie bereits erw?hnt: Ich m?chte nicht mein Leben einem Programm von
: jemandem anvertrauen, dem es ?kompliziert? erscheint,
: integer-?berl?ufe im Quelltext sinnvoll zu behandeln und der ein


: Spezialtool braucht, um potentielle zu finden. Dazu gibt es zuviele

: esoterische Fehlerm?glichkeiten.
:
:> Dein Problem, ich schreibe keine Software, um mit Compiler und


:> Debugger zu kaempfen, ich schreibe Software, um etwas zum Laufen zu
:> bekommen.
:

: Vermutlich w?re ?davonlaufen? anzuraten.


:
:> >> Das einzige, was Dir fehlt, sind gotos (braucht
:> >> man die?)

:> >
:> > ?Man? benutzt sie st?ndig, was vom Compiler mehr oder minder hinter


:> > einem Feigenblatt verborgen wird.
:>
:> *Das* weiss ich selbst.
:

: Warum fragst Du dann? Du wei?t sicher auch, da? die meisten


: Kontrollstrukturen prinzipiell redundant sind und der Bequemlichkeit/

: ?bersichtlichkeit halber verwendet werden.


:
: ----------------------
: p = pacct->gr_mem;
: while (1) {
: if (!*p) break;
: if (strcmp(*p, user->pw_name) == 0) {
: if (argv[1]) log_access(user->pw_name, argv + 1, argc - 1);
: goto found;
: }
:
: ++p;
: }
:
: setuid(uid);
: }
:
: found:
: execve(COMMAND, argv, env);
: perror("execve");
: ----------------------

:
: F?r goto gilt das desgleichen.


:
:> > Obiges gilt entsprechend: Objekte im RAM haben eine Adresse, die die
:> > CPU benutzt, um sie zu adressieren.
:>
:> Und? Deswegen muss ich das Objekt auf Source-Ebene nicht mit seiner
:> Adresse ansprechen.
:>
:> Da kannst Du auch gleich wieder Assembler programmieren.
:
: Das Gegenteil von A ist !A und nicht B. Es bringt nichts, die Adressen
: wegzuabstrahieren, also wozu tun?
:
:> >> Was ich mit SHOLIS meinte: Wenn mit SPARK ein System beschreiben
:> >> kann, welches die sicherheitskritische Software eines Helikopters
:> >> darstellt,
:> >

:> > Es ist ?bewiesen?, da? man so ein System in Visual Basic beschreiben


:> > kann.
:>
:> So, kann man das?
:

: Ja und zwar wegen 'turing vollst?ndig'.

--
---
Microsoft Windows--a fresh perspective on information hiding

Rainer Weikusat

unread,
Jan 29, 2003, 3:14:08 AM1/29/03
to
Stefan Nobis <ste...@snobis.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
> > Das «Verständnis» sagt per se gar nichts aus. Aber der Quelltext tut
> > das: Er ist eine vollständige Beschreibung dessen, was die Software zur
> > Laufzeit tun wird.
>
> Davon träumst du, oder?

Eine nichtdeterministische Maschine kann ich auch «formal» nicht
«verifizieren». Das sich praktische Vorteile dadurch ergeben, daß die
Semantik unter der Annahme einer deterministischen Maschine bekannt
und sinnvoll ist, sollte nachvollziehbar sein.

> > dem Programmierer überlassen. Falls man dem vorher nicht zutrauen
> > konnte, faktisch korrekten Code zu schreiben (insofern möglich), warum
> > sollte er es hinterher plötzlich können?
>
> Wenn es um kritische Systeme geht, kann man getrost davon ausgehen,
> dass *kein* einziger Mensch jemals korrekten, sprich 100%
> fehlerfreien, Code schreibt.

Gründet sich die Annahme, daß die Mehrzahl aller «kritischen» Systeme
mehr oder minder irreparabel kaputt ist, eigentlich auf praktische
Erfahrungen? Gruselig ...

> Ziel muss es also sein, einerseits Fehler verstärkt zu vermeiden und
> es gibt Möglichkeiten, die (durchschnittliche) Fehlerquote beim
> Programmieren mit diversen Mitteln zu reduzieren. Andererseits
> versucht man möglichst automatisiert Fehler zu finden

«Die Achterbahn des Schreckens, Teil II». Ist Dir klar, das jede
automatisch verhinderte «Fehlerklasse» ein weiterer kludge ist, der
um einen mittlerweile bekannten möglichen Fehler herumwürgt?

> > Wegen einer formalen Beschreibung ohne Fehler
> > bekomme ich keinen Quelltext ohne Fehler, und (zum 1000x):
>
> Natürlich nicht.
>
> > Ein Programm ist bereits eine formale Beschreibung.
>
> Aber auf einem völlig anderen Abstraktionsniveau. Auf diese Weise
> bekomme ich etliche neue Fehlerquellen.

Zwischenschritt eliminieren ;-).

> > > Eine Registermaschine ist auch turing-vollstaendig. Warum also C?
>
> > C-Programme beschreiben normalerweise Registermaschinen.
>
> So ein Quark. C basiert noch nicht einmal auf einer klaren
> Maschinenbeschreibung (wie z.B. Lisp) und noch viel weniger
> beschreiben C Programme eine Registermaschine (welchen Sinn sollte das
> auch machen) -- du selbst hast doch gesagt, Quelltext beschreiben, was
> zur Laufzeit passiert. Wie sollen sie außerdem auch noch Maschinen
> beschreiben?

Offensichtlich kann man jedes Programm in einer imperativen
Programmiersprache auch als spezialisierten IC realisieren. Ein
Programm ist eine virtuelle Maschine, die auf einer etwas
allgemeineren simuliert wird.

> [Spielzeugsprache]
> > ZB eine ohne dynamische Speicherverwaltung und ohne
> > Rekursionen. Insbesondere letzteres mutet abstrus an, denn gerade
> > rekursive Algorithmen kann man oft einfach durch Induktion beweisen.
> [...]
> > Wie bereits erwähnt: Ich möchte nicht mein Leben einem Programm von
> > jemandem anvertrauen, dem es «kompliziert» erscheint,
> > integer-Überläufe im Quelltext sinnvoll zu behandeln und der ein
> > Spezialtool braucht, um potentielle zu finden. Dazu gibt es zuviele
> > esoterische Fehlermöglichkeiten.
>
> Und eben weil es viele esoterische Fehlermöglichkeiten gibt, sollte
> man alle Möglichkeiten, Fehler zu vermeiden, nutzen. Wieso nicht
> gleich eine Sprache, bei der etliche Fehlerklassen (z.B. wilde Zeiger)
> schlicht unmöglich sind?

Weil das praktisch eine non-issue ist und in jedem anderen Fall ist
der Quälcode Sondermüll und gehört als solcher behandelt zu werden.

> Wieso sind einige Abstraktionskonzepte, wie Rekursionen u.a., wichtig
> und gut und andere wieder völlig überflüssig und böse?

Ich hatte nichts von «überflüssig» oder «böse» geschrieben.

> > > Und? Deswegen muss ich das Objekt auf Source-Ebene nicht mit seiner
> > > Adresse ansprechen.
>
> > > Da kannst Du auch gleich wieder Assembler programmieren.
>
> > Das Gegenteil von A ist !A und nicht B. Es bringt nichts, die Adressen
> > wegzuabstrahieren, also wozu tun?
>
> Um Fehlerquellen zu vermeiden. Mit Adressen, zumal ihrer
> Repräsentation(!) in C, kann man rechnen,

Das ist bei Werten so üblich.

> mit Referenzen (einer anderen Repräsentation) kann man nicht rechnen
> -- damit sind wilde Zeiger z.B. (nahezu) unmöglich.

Das hat nichts mit «Rechnen» zu tun, sondern damit, ob die abstrakte
Maschine, die von der Sprache beschrieben wird, Referenzen mit
beliebigen Werten gestattet.

Rainer Weikusat

unread,
Jan 29, 2003, 4:02:44 AM1/29/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Rainer Weikusat wrote:
> > Tut mir leid, aber das ist definitiv nicht mehr komisch.
>
> Eben. Aber Deinen Aussagen nach zu urteilen, die darauf schliessen
> lassen, dass Du ausschliesslich dem "faehigen Programmierer" vertraust,
> koennen Deine Massstaebe an Software nicht allzu hoch sein.

Du behauptest das ständig, obwohl ich fortwährend das Gegenteil
schreibe.

> > Das «Verständnis» sagt per se gar nichts aus. Aber der Quelltext tut
> > das: Er ist eine vollständige Beschreibung dessen, was die Software
> > zur Laufzeit tun wird.
>
> Nein, diese Beschreibung ist mitnichten vollstaendig. Was tut das
> System, wenn die Software einen Zeiger dereferenziert, der auf ein
> zufaellig bereits freigegebenes Objekt zeigt?

Wie passiert das ohne im Quellcode auffindbar zu sein?

> Was passiert, wenn mit den Ergebnissen aus uninitialisierten
> Variablen gerechnet wird?

Dann wird mit uninitialsierten Variablen gerechnet. Das konkrete
Ergebnis ist falsch und somit egal.

> Das ganze ist nicht einmal mehr deterministisch, was willst Du da
> mit dem Source anfangen?

Beides korrigieren. Warum?

> Und *Du* kannst bei 100KSLOC *garantieren*, dass keiner dieser Fehler
> auftritt?

Spielt das eine wesentliche Rolle, falls man das muß?

> >> Und es wohl kaum moeglich, ein 100'000 Zeilen-Programm vollstaendig
> >> zu verstehen und garantieren zu koennen, dass es das tut, was es tun
> >> soll, unter allen Umstaenden.
> >
> > Es ist möglich, eine 100.000-Zeilen-Programm so zu konstruieren, daß
> > man keine Einheiten von mehr als maximal tausend Zeilen hat und so,
> > daß diese Einheiten keine internen Abhängigkeiten haben.
>
> Ja. Was nicht heisst, dass es nachher funktioniert.

Falls der Entwurf Müll war, bekommt man ein korrektes Programm, das
Müll tut.

> > Die Grundvoraussetung für das, was ich geschrieben hatte
> > («Tolerabilität von fringe case-Fehlersituationen»), ist, daß das
> > System deswegen nicht Amok läuft, was man durch einen geeigneten
> > internen Aufbau sicherstellt.
>
> Und in SPARK durch den Beweis der Abwesenheit von Laufzeitfehlern
> garantieren kann.

Lies das bitte mal durch

<URL:http://www.freesoft.org/CIE/RFC/1035/43.htm>

und erkläre mir bitte danach, wie eine Überlaufprüfung mir gegen data
corruption, die aufgrund einer verpeilten Implementierung ohne das
höchstwertige Bit im Offset auftritt, falls es für die befragte zone
soviel secondaries gibt, daß in der addtional info section
Rückverweise > 255 vorkommen.

> >> It is easier to fit the specification to a program than vice versa?
> >
> > Entweder das Programm ist eine Übersetzung der Spezifikation in eine
> > andere Sprache oder Du hast einen schrecklichen Fehler gemacht, der
> > sich auch mit 400t glue code im Nachhinein nicht mehr wird
> > reparieren lassen.
>
> Sorry, entweder Du traeumst oder Du bist einer von denen, die immer auf
> Anhieb korrekte, der Spezifikation entsprechende Software schreiben
> koennen. Wieviele Fehler hast Du im Durchschnitt pro Tausend Zeilen
> Code?

Das ist die falsche Frage. «Wie lange dauert es, bis 1000 Zeilen Code
fehlerfrei sind?»

> BTW, auch die Spezifikation kann falsch sein bzw. Inkonsistenzen
> haben.

Das ist dann allerdings Pech, aber auf einer anderen Ebene.

> Beim MultOS-CA hat man 38 Fehler aus der Spezifikationsphase erst in
> der Kodierphase gefunden und einen waehrend der Operation.

Zuviele Details.

> > Wie käme ich denn dazu? Wegen einer formalen Beschreibung ohne Fehler
> > bekomme ich keinen Quelltext ohne Fehler,
>
> In SPARK hast Du sehr gute Chancen dazu.
>
> > und (zum 1000x): Ein Programm ist bereits eine formale Beschreibung.
>
> LOL
>
> Ein formale Beschreibung, deren Konsistenz Du bitte
> *wie* nachweist?

Wem gegenüber?

> >> >> So die Theorie und in den vielen Faellen mag das stimmen. Laut Rod
> >> >> (und ich glaube da einfach mal seiner Erfahrung) findet man die
> >> >> meisten Fehler aber, wenn man diese einzelnen Unit zusammenfuegen
> >> >> will, also letztendlich im Interface. Das ist im uebrigen auch
> >> >> meine Erfahrung.
> >> >
> >> > Das ist eine groteskte Horrortheorie,
> >>
> >> Diese Theorie stammt von Dir, danke.
> >
> > Warum sollte ich mich denn vollkommen widersinnig auf meinen Text
> > beziehen anstelle auf Deinen?
>
> Weil ich auf Deinen Text bezogen "So die Theorie" schrieb.

<URL:http://www.google.de/search?q=thematische+progression&ie=UTF-8&oe=UTF-8&hl=de&btnG=Google-Suche&meta=>

> > Bei allen Dingen, mit denen ich praktisch zu tun habe, und dazu gehört
> > Quellcode anderer Leute mit dazu, verhält sich das genau umgekehrt, dh
> > der Code tut nicht das, was das Interface angeblich bereitstellt.
>
> Dann solltest Du die Leute grundsaetzlich wegen Unfaehigkeit feuern.

Ich behelfe mir lieber damit, nichts wiederzuverwenden, was trivial
reimplementierbar ist.

> >> > deren Implikationen ausschließlich besagen, daß die Resultate
> >> > lebensgefährlich sein werden.
> >>
> >> Interessant. Wie kommst Du darauf?
> >
> > Ich denke nicht, daß ich das Dir in einem Usenet-angemessenen Rahmen
> > erklären kann, aber jedenfalls würde ich nie so wahnsinnig sein, mein
> > Leben einem Computerprogramm anzuvertrauen, auf das diese Aussage
> > zutrifft, falls ich nicht ohnehin Hazard spiele.
>
> Irgendwie habe ich jetzt was nicht ganz begriffen.

Das, wovon Du redest, würde ich «design flaws» im Interface
nennen. Falls die häufiger sind als Tippfehler, würde ich «Rennt um
euer Leben» als einzige adäquate Reaktion empfehlen.

> Ansonsten, steige bitte nie wieder in ein Flugzeug, vor allem nie weider
> in eine Boeing. Das ist lebensgefaehrlich.

Vermutlich. Aber das kürzlich für den häufigsten Luftfahrtunfall heißt
«CIFT», was für «controlled flight into terrain» steht, dh der Pilot
fliegt gegen den Berg und warum bleibt ein Geheimnis.

> Die Software haben nicht nur unfaehige Idioten geschrieben, die zu
> bloed sind, Integer-Ueberlaeufe schon im Source zu erkennen,

Wenn Du sie so nennen magst.

> >> Ich bin immer noch nicht ganz dahintergekommen, was Du mit
> >> Spielzeugsprache meinst.
> >
> > ZB eine ohne dynamische Speicherverwaltung
>
> Brauche ich wirklich selten. Und in Embedded Systems- bzw.
> Safety-Critical-Umgebungen will man das auch nicht. Es wird Dir in
> den seltensten Faellen gelingen, nachzuweisen, dass Deine Techniken
> nicht zu Speicherfragmentierung und/oder Memory-Leaks fuehren.

Bitte? «Man kann keine Algorithmen schreiben, deren Speicherverbrauch
über die vollständige Laufzeit O(1) ist?», sagen wir mal trivial
dadurch, daß man eine maximale Anzahl an mallocs durchführt und die
allozierten Objekte weiterverwendet. Das gibt dann eine Invariante,
der die Eingabedaten genügen müssen und andernfalls hat man einen
korrigierbaren Ausnahmezustand.

> > und ohne Rekursionen.
>
> Der SPARK-Examiner selbst ist in SPARK geschrieben. Und ja, der Parser
> ist statisch verifiziert und benutzt weder Rekursion noch dynamischen
> Speicher. Rod war natuerlich durchaus der Meinung, dass das nicht sehr
> einfach war.
>
> > Insbesondere letzteres mutet abstrus an, denn gerade
> > rekursive Algorithmen kann man oft einfach durch Induktion beweisen.
>
> Auch deren Stackverbrauch, bevor die Runtime-Umgebung ein Storage_Error
> ausloest (oder halt nicht)?

In Abhängigkeit von den Eingabedaten. Klar. Wieso?

> >> Eine Sprache, die es einfacher macht, korrekten Code zu schreiben,
> >> weil das dann ja jedes Kind tun kann?
> >
> > Wie bereits erwähnt: Ich möchte nicht mein Leben einem Programm von
> > jemandem anvertrauen, dem es «kompliziert» erscheint,
> > integer-Überläufe im Quelltext sinnvoll zu behandeln
>
> Falls Du das auf mich beziehst:

Ich halte Dich eigentlich nicht für ein Programm, lasse mich aber
gerne eines besseren belehren.

> > und der ein Spezialtool braucht, um potentielle zu finden.
>
> Wenn Du das so meinst. Demzufolge sollten sicherheitskritische Programme
> in

Sprachen geschrieben werden, die die verwantwortlichen Autoren auch
beherrschen. Solche Anforderungen sind für Übersetzer(!!)
selbstverständlich und die entwerfen keine «kritischen
Systeme». Welche ist vollkommen wurscht.

[...]

Das ist eine Schleife mit drei Abbruchbedingungen, von denen Du eine
willkürlich im Schleifenkopf positioniert hast. Ich halte das für eine
Verwirrtaktik und brauchst wegen der Zählerei 'grundsätzlich' eine
Überlaufprüfung. Für den Wert gibt es möglicherweise eine konstante
Obergröße, aber keine definierte Länge (... die nicht erst durch
Zählen ermittelt werden müßte).

> > Das Gegenteil von A ist !A und nicht B. Es bringt nichts, die Adressen
> > wegzuabstrahieren,
>
> Aber sicher bringt das etwas.
>
> > also wozu tun?
>
> Deswegen:
>
> |void something (char* blabla)
>
> vs.
>
> |procedure Something (BlaBla : in Char_Array);
>
> vs
>
> |procedure Something (Blabla : out Char_Array);
>
> Jetzt versuche mal, den drei Funktionen eine Nullzeiger zu uebergeben
> und bei der C-Variante zu erzaehlen, ob blabla veraendert wird.
>
> Manchmal sind Abstraktionen der bessere Weg.

Das halte ich für «debatable». Weniger Komplexität ist der bessere
Weg.

Rainer Weikusat

unread,
Jan 29, 2003, 4:09:54 AM1/29/03
to
Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
> : denn daf?r ist sie da. Ich mu? allerdings gestehen, Dir nicht ganz
> : folgen zu k?nnen.
>
> Ich wollte andeuten, dass es nicht mehr einfach ist, die Bedeutung
> einer Hochsparchen-Operation im Detail pruefen oder vorher sagen
> zu koennen:
> In einem nebenlaeufigen Programm sei '=' im Quellcode angetroffen.
> Was genau, im hinblick auf die betroffenen Daten (lhs, rhs),
> im Hinblick auf die betroffenen Programm-Teile,
> im HInblick auf die Stack-Nutzung,
> im Hinblick auf die heap-Nutzung,
> im Hinblick auf die waehrend '=' ablaufenden clock ticks,
> bedeutet '='?

Das ist alles herzlich irrlevant, denn es handelt sich bis auf den
ersten um externe Faktoren (dh Gegenstände einer getrennten
Betrachtung).

> Faellt es dir hier so leicht, sagen wir innerhalb von 2 min,
> diese Angaben fuer einen Echtwelt-Wartungsfall zu machen?

Es sollte.

> :> Jedes turing-vollstaendige setup koennte Speichersammlung
> :> bereitstellen. Wer/was schuetzt die Steuerung des Roentgen-Kastens
> :> davor, dass das jemand versehentlich genutzt hat?
>
> : Wovon sprichst Du?
>
> EIn Roentgen-Geraet hat eine Bestrahlungs-Dauer die nicht ueberschritten
> werden darf. Sollte in einem Programm garbage collection erlaubt
> sein kann dabei Zeit drauf gehen, vielleicht im falschen Moment: der
> Bestrahlung. Wenn doch ein tool solchen sonst sinnvollen Sprachgebrauch
> an dieser Stelle verhindern hilft, was ist dagegen einzuwenden?

«Garbage Collection» und «Echtzeit» dürften sich wohl gegenseitig
ausschließen (nicht notwendigerweise: man kann vermutlich
inkrementelle gc mit festen Zeitgrenzen implementieren).

> :> Die Behauptungen, die in einem Programm-Quelltext enthalten sind,
> :> koennen glaube ich ohne Gesichtsverlust explizit gemacht werden,
>
> : Sie sind es bereits.
>
> Kommt drauf an. Wenn irgendwo long in einem C Programm steht,
> ist damit noch nicht gesagt, welche Teilmenge von Zahlen in der
> entsprechenden Groesse enthalten sein werden.

Für jede Implementierung schon. Gegen Fehlverwendung hilft das
allerdings wenig.

> (Assertions als Beispiel zur Explizitheit des semantischen
> Inhalts eines Programms: Sie sind in einigen Sprachen
> mehr, in anderen weniger explizit angebbar. Es sei denn du findest
> es vorteilhaft, wenn die Programmierer, sagen wir die von dir
> genannten "Engineers", diese Pruefungs-Anweisungen und deren Handling
> repetitiv und explizit selbst schreiben, Mechanismen, die sonst in
> Sprachen enthalten sind.)

Kaum.

Rainer Weikusat

unread,
Jan 29, 2003, 4:14:35 AM1/29/03
to
Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
> : ZB eine ohne dynamische Speicherverwaltung und ohne
> : Rekursionen. Insbesondere letzteres mutet abstrus an, denn gerade
> : rekursive Algorithmen kann man oft einfach durch Induktion beweisen.
>
> Daran kein Zweifel. Aber, und da glaube ich scheint ein
> entscheidendes Misverstaendnis vor zu liegen, es geht bei SPARK
> zunaechst um Systeme, bei denen Speicher fuer heutige Verhaeltnisse
> abstrus knapp sein kann. So knapp, dass Rekursion (direkte und
> indirekte) deswegen (implizit) nicht zugelassen ist, weil im
> allgemeinen Fall fuer den Funktions-Aufruf stack-speicher, und
> zwar in statisch nicht vorhersagbarer Menge, benoetigt werden wird.
> Das ist hier entscheidend.

Die Speichermenge, die benötigt wird, hängt von den Eingabedaten
ab.

> Es geht u.a. um statische Vorhersagbarkeit des verbrauchten
> stack-Speichers: Es muss sicher gestellt sein, dass das Programm,
> so wie du auch gefordert hast, nicht an die Decke knallt, sozusagen,
> Oder amok laeuft, sondern sich faengt, vorhersagbar verhaelt,
> und dafuer muss im allgemeinen Fall Speicher da sein.
>
> Beispiel: Die Steuerung einer automatischen Tuer hat in einem
> aussergewohlichen (tolerablen?) Fall jemanden eingeklemmt. Wenn
> - ich Rekursion im Steuerprogramm nach belieben erlaube, und
> - Funktionen Seiteneffekte zB auf elektrisches Geraet haben duerfen,
>
> dann kaenn es sein, dass kein stack-speicher da ist, um reset-Routinen
> aufzurufen. Ich koennte verlangen, dass dann stack speicher fuer
> solche Faelle reserviert ist, aber wieviel, wenn rekursion etc
> zugelassen ist? Ich koennte verlangen, dass der Aufrufstapel einfach
> abgeraeumt wird, aber habe ich dann noch hinreichend Information
> ueber der Zustand von Variablen, die den Zustand externer GEraete
> aufgezeichnet haben? Alles in statisch reservierten Variablen
> speichern?

Das war doch das projektierte Modell.

> Auswege sind offenbar nicht immer leicht zu finden, und ohne
> Zweifel ist ein geeigneter System-Entwurf unentbehrlich. Aber
> ich weiss immer noch nicht, was gegen den Einsatz eines tools
> spricht, dass eine Sprache verarbeitet, die mir beim Umsetzen
> eines Entwurfs nach Implementations-Richtlinien "auf die Finger
> schaut". Ich denke, es gibt nicht viele Leute, die so gut sind
> wie sozusagen ein compiler, runtime-experte, Korrektheits-Pruefer
> und "O(f(n))-Beweiser" in einer Person.

Man sollte schon wissen, was man für Laufzeitverhalten zusammenbaut.

> Ist zB lint (lclint, splint) ein ebenso verwerfliches Werkzeug?

Wieso verwerflich?

Stefan Nobis

unread,
Jan 29, 2003, 5:36:43 AM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> Stefan Nobis <ste...@snobis.de> writes:
> > Rainer Weikusat <weik...@students.uni-mainz.de> writes:
> > > Das «Verständnis» sagt per se gar nichts aus. Aber der Quelltext tut
> > > das: Er ist eine vollständige Beschreibung dessen, was die Software zur
> > > Laufzeit tun wird.

> > Davon träumst du, oder?

> Eine nichtdeterministische Maschine kann ich auch «formal» nicht
> «verifizieren». Das sich praktische Vorteile dadurch ergeben, daß die
> Semantik unter der Annahme einer deterministischen Maschine bekannt
> und sinnvoll ist, sollte nachvollziehbar sein.

Es wäre schön, wenn du, mal zur Abwechslung, auf die Kernaussagen
eingehen könntest, statt wahllos themenflucht zu begehen.

Wieso schafelst du von nichtdeterministischen Maschinen? Was tut das
zur Sache? Es geht um konkrete, deterministische Rechner, reale
Computer mit Betriebssystemen, vielen Bibliotheken, Laufzeitumgebung
der verwendeten Programmiersprache etc.

Und in diesem Kontext ist der Quelltext eben gerade keine
*vollständige* Beschreibung dessen, was die Software zur Laufzeit tut,
schon allein deswegen, weil der Quelltext gar keine semantische
Beschreibung von aufgerufenen Bibliotheksroutinen oder Syscalls
enthält. Deren Semantik ist aber durchaus wesentlich für das
Laufzeitverhalten eines Programmes.

In einem Bibliotheksaufruf wie "open(...)" steckt natürlich eine
Andeutung, was hier zur Laufzeit passieren *sollte*! Es ist aber keine
*vollstädinge* Beschreibung des Laufzeitverhaltens. Das ist ein sehr
wichtiger Unterschied.

> > > dem Programmierer überlassen. Falls man dem vorher nicht zutrauen
> > > konnte, faktisch korrekten Code zu schreiben (insofern möglich), warum
> > > sollte er es hinterher plötzlich können?

> > Wenn es um kritische Systeme geht, kann man getrost davon ausgehen,
> > dass *kein* einziger Mensch jemals korrekten, sprich 100%
> > fehlerfreien, Code schreibt.

> Gründet sich die Annahme, daß die Mehrzahl aller «kritischen» Systeme
> mehr oder minder irreparabel kaputt ist, eigentlich auf praktische
> Erfahrungen? Gruselig ...

Ich schrieb, dass kein Mensch 100% fehlerfreien Code zu schreiben in
der Lage ist. Das Gegenteil müsstest du mir erstmal beweisen, da es
diverse Studien gibt, die empirisch nachgewiesen haben, dass ab
ca. 30.000 bis 50.000 Zeilen Quelltext garantiert eine gewisse
Mindestzahl an Fehlern vorhanden ist.

Allerding entschuldige ich mich für eine grobe Ungenauigkeit:
Natürlich beziehen sich solche Fehlerbetrachtungen erstmal nur auf
direkt geschriebenen Quelltext, ohne aufwendige(!) Fehlersuche und
Tests. Wenn man also einen Programmierer hinsetzt und Code schreiben
lässt[1], dann wird, je nach Komplexität und Umfang des
Gesamtprojekts, dabei eine gewisse Fehlerquote garantiert
auftreten.

Und solche Fehler eliminiert man eben nur mit sehr aufwendigen (und
leider teuren) Verfahren. Das Genie, dass nur mit Texteditor und
Compiler bewaffnet ohne weitere (technische) Hilfsmittel (von Doku mal
abgesehen :)), fehlerfreie Systeme mit mehreren zehntausend Zeilen
Quelltext erstellen kann, musst du mir echt mal zeigen.

Die kritischen Systeme bekommt man dann eben nur durch sehr formelle
und aufwendige Verfahren doch noch hinreichend fehlerfrei. Das dies,
egal ob Software und/oder elektronik überhaupt im Spiel ist, niemals
in jedem Fall zu 100% gelingt, zeigen die vielen Beispiele von
katastrophalen Fehlern bei kritischen Systemen. Merke: Menschen
produzieren niemals garantiert 100% fehlerfrei Produkte, egal in
welchem Bereich. Menschen machen Fehler und ein Mensch macht auch sehr
häufig denselben Fehler mehrmals.

[1] Den er selbst natürlich nachträglich nochmal lesen und
korrigieren darf und auch einfache, oberflächliche Tests sind noch
erlaubt -- also Compiler mit max. Warnungen, einfache Testläufe mit
aktiven asserts; halt so dass, was üblicherweise vor dem Einchecken in
CVS oder ähnliches gemacht wird.

> «Die Achterbahn des Schreckens, Teil II». Ist Dir klar, das jede
> automatisch verhinderte «Fehlerklasse» ein weiterer kludge ist, der
> um einen mittlerweile bekannten möglichen Fehler herumwürgt?

Könntest du das mal näher ausführen? Ich verstehe nicht, was du
meinst.

Oder spielst du darauf an: Mensch kennt ja die möglichen
Fehlerquellen, also sollte es kein Problem sein, die Fehler zu
vermeiden.

Und du hast ja auch noch nie in deinem Leben einen Fehler ein zweites
Mal begangen, gelle.

Mal konkret: Wie stellst du dir eigentlich die Entwicklung von
z.B. der Steuer-Software der Ariane vor? Auf die Genialität der
Programmierer hoffen, die schon keine Fehler machen oder die zwei, die
doch mal passieren, problemlos während eines kurzen Debuggings finden?

Das ist deine ganze Qualitätskontrolle? Und verlässt dich blind auf
ein Team von vielleicht hundert Programmierern? Du kannst in solchen
Teams für die Qualität und Fehlerfreiheit jedes einzelnen Menschen
garantieren? Wie?

> > Aber auf einem völlig anderen Abstraktionsniveau. Auf diese Weise
> > bekomme ich etliche neue Fehlerquellen.

> Zwischenschritt eliminieren ;-).

Abstraktions- und Kontrollebenen eliminiert. Für die Entwicklung eines
sicheren und robusten LDAP-Servers wahrscheinlich sinnvoll, für obiges
Beispiel der Ariane-Steuerung, zumal bei großen Teams mit den dabei
auftretendem Kommunikationsoverhead und -problemen, halte ich es für
ein sehr großes Problem, diese Zwischenschritte zu eliminieren.

Diese Zwischenschritte erlauben in einem (größeren) Team eine bessere
Kommunikation, da durch eine gemeinsame, formalisierte Sprache erstmal
dafür gesorgt wird, dass auch wirklich alle von derselben Sache
sprechen und dasselbe meinen. Die Quelltextebene wäre hier (bei
komplexen Systemen und größeren Teams) zu sehr mit Details belastet,
so dass der Blick für das Wesentliche zu schnell verloren geht.

> > > C-Programme beschreiben normalerweise Registermaschinen.

> > So ein Quark. C basiert noch nicht einmal auf einer klaren

> Offensichtlich kann man jedes Programm in einer imperativen


> Programmiersprache auch als spezialisierten IC realisieren. Ein
> Programm ist eine virtuelle Maschine, die auf einer etwas
> allgemeineren simuliert wird.

Eine Registermaschine ist ein klar definierter Begriff. Und eine
solche Registermaschine wird durch kein C Programm beschrieben (man
kann aber C Programme in Programme für Registermaschinen übersetzen).

Buzzwords und schwammige Ausdrucksweisen helfen dir da nicht weiter.

Und um in deinem Begriffswirrwarr zu bleiben: Dadurch, dass VM A auf
VM B simuliert wird, ist VM A nicht gleich eine Beschreibung von VM
B.

> > Und eben weil es viele esoterische Fehlermöglichkeiten gibt, sollte
> > man alle Möglichkeiten, Fehler zu vermeiden, nutzen. Wieso nicht
> > gleich eine Sprache, bei der etliche Fehlerklassen (z.B. wilde Zeiger)
> > schlicht unmöglich sind?

> Weil das praktisch eine non-issue ist und in jedem anderen Fall ist
> der Quälcode Sondermüll und gehört als solcher behandelt zu werden.

Ah! Verstehe. Also ist nichts gegen möglichst viele Fehlerquellen in
einer Sprache einzuwenden, weil ja gute Programmierer nicht auf solch
dumme Fallen reinfallen und keine Probleme damit haben, jegliche
Fehler zu vermeiden.

Wo bitte waren doch gleich diese absolut fehlerfreien Programme, die
es ja deiner Aussage nach offensichtlich geben muss. Denn gute
Programmierer machen ja keine Fehler.

Alle deine nicht-trivialen Programme sind völlig fehlerfrei? Da wurde
noch nie ein Fehler in einem deiner Programme gefunden, nachdem du sie
für den produktiven Einsatz freigegeben hattest? Alle Achtung, ich bin
sehr beeindruckt (oder schreibst du nur sehr kleine Programme).

Bleibt nur die Frage wie viele solcher Genies es gibt, die fehlerfrei
programmieren können. Ob die Anzahl reicht, um den realen Bedarf an
Software zu decken? Ich habe da so meine Zweifel.

Und für alle die armen, im Grunde unfähigen Programmierer, die eben
doch ab und zu mal einen Fehler im Quelltext machen, den sie nicht
alleine finden, gibt es eben Hilfen, die bestimmte, typische Fehler zu
vermeiden helfen.

Ich für meinen Teil habe auch kein Problem damit, zuzugeben, dass ich
niemals fehlerfrei arbeite, dass ich nicht perfekt bin und daher immer
wieder mal auf Hilfe (von anderen Menschen oder von Werkzeugen)
angewiesen bin, um meine Fehlerquote zu reduzieren. Und ich vermute,
dies trifft auf viele Menschen in allen Tätigkeitsbereichen zu.

Langsam frage ich mich ernsthaft, wie dein Menschenbild aussieht.

> > Wieso sind einige Abstraktionskonzepte, wie Rekursionen u.a., wichtig
> > und gut und andere wieder völlig überflüssig und böse?

> Ich hatte nichts von «überflüssig» oder «böse» geschrieben.

Nicht wörtlich, aber deine Aussagen suggerierten dies. So hälst du es
für überflüssig und sinnlos, Speicheradressen zu abstrahieren und
z.B. das Rechnen und beliebige Manipulieren von diesen zu verbieten,
da ja gute Programmierer all die offensichtlichen Fehlerquellen leicht
vermeiden können und daher (zumindest in diesem Punkt) niemals Fehler
begehen.

Genau solche Mechanismen sind Abstraktionskonzepte und neben anderen
Aspekten helfen sie (evtl.) auch Fehlerquellen zu vermeiden (was ja
richtige Programmierer niemals nötig hätten).

> > Um Fehlerquellen zu vermeiden. Mit Adressen, zumal ihrer
> > Repräsentation(!) in C, kann man rechnen,

> Das ist bei Werten so üblich.

Bei Konstanten nicht.

> > mit Referenzen (einer anderen Repräsentation) kann man nicht rechnen
> > -- damit sind wilde Zeiger z.B. (nahezu) unmöglich.

> Das hat nichts mit «Rechnen» zu tun, sondern damit, ob die abstrakte
> Maschine, die von der Sprache beschrieben wird, Referenzen mit
> beliebigen Werten gestattet.

Nein, das hat damit zu tun, dass der Ausdruck "Referenz"
i.a. impliziert, dass es sich um etwas relativ konstantes handelt,
d.h. man kann immer nur ein existierendes Objekt referenzieren und
nicht eine beliebige Speicheradresse (es sei denn, diese wäre ein
zulässiges Objekt, was jedoch in den meisten Sprachen, die solche
Abstraktionskonzepte bieten, nicht der Fall ist).

Referenzen können also sehr wohl beliebige Werte annehmen, jedoch muss
dieser Wert zu einem exitierenden, gültigen (dereferenzierbaren)
Objekt gehören.

--
Stefan.

Stefan Nobis

unread,
Jan 29, 2003, 5:56:08 AM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> > > Das «Verständnis» sagt per se gar nichts aus. Aber der Quelltext tut
> > > das: Er ist eine vollständige Beschreibung dessen, was die Software
> > > zur Laufzeit tun wird.

> > Nein, diese Beschreibung ist mitnichten vollstaendig. Was tut das
> > System, wenn die Software einen Zeiger dereferenziert, der auf ein
> > zufaellig bereits freigegebenes Objekt zeigt?

> Wie passiert das ohne im Quellcode auffindbar zu sein?

Falsche Frage! Du hast behauptet, der Quelltext sei eine
*vollständige* Beschreibung dess, was die Software zur Laufzeit tun
wird. Was also tut die Software bei einem solchen Fehler? Du kannst
das nicht ausschließlich aus dem Quelltext heraus beantworten, weil du
die exakte Semantik bestimmter Bibliotheksfunktionen kennen musst?
Richtig. Also kann der Quelltext keine *vollständige* Beschreibung des
Laufzeitverhaltens sein.

> > Und *Du* kannst bei 100KSLOC *garantieren*, dass keiner dieser Fehler
> > auftritt?

> Spielt das eine wesentliche Rolle, falls man das muß?

Wenn ein solcher Fehler u.U. Menschenleben kosten kann, spielt es eine
sehr große Rolle, ob du die Fehlerfreiheit garantieren kannst. Ganz
besonders, wenn du als Entwickler persönlich für alle Folgen der von
dir gemachten Fehler verantwortlich gemacht wirst.

> Das ist die falsche Frage. «Wie lange dauert es, bis 1000 Zeilen Code
> fehlerfrei sind?»

Nein, du stellst hier die falsche Frage. Woher weißt du, dass in
deinem Quelltext keine weiteren Fehler sind? Wagst du es wirklich,
Software für kritische Systeme zu schreiben und für jeden auftretenden
Fehler persönlich zu haften?

Wenn jemals in einem der von dir geschriebenen Programme ein Fehler
auftauchte/gefunden wurde, nachdem du das Programm für den
Produktionsbetrieb freigegeben hattest, solltest du ganz schnell mal
von deinem hohen Ross 'runterkommen.

> > Ein formale Beschreibung, deren Konsistenz Du bitte
> > *wie* nachweist?

> Wem gegenüber?

Den Angehörigen des Opfers deiner Fehler... und dem Staatsanwalt, der
dich wegen fahrlässiger Tötung anklagt.

> Bitte? «Man kann keine Algorithmen schreiben, deren Speicherverbrauch
> über die vollständige Laufzeit O(1) ist?», sagen wir mal trivial
> dadurch, daß man eine maximale Anzahl an mallocs durchführt und die
> allozierten Objekte weiterverwendet. Das gibt dann eine Invariante,

Und? Damit hast du effektiv eine statische Speicherverwaltung und der
Kern der dynamischen Speicherverwaltung, nämlich die
Unvorhersehbarkeit des notwendigen Speichers, bleibt außen vor.

Dann kann man aber eigentlich auch gleich auf die mallocs
verzichten. :)

> Sprachen geschrieben werden, die die verwantwortlichen Autoren auch
> beherrschen. Solche Anforderungen sind für Übersetzer(!!)

Wobei du unter "beherrschen" offensichtlich verstehst, dass man keine
Fehler macht (die man nicht trivial in ein paar Stunden debugging
garantiert findet und eliminiert).

Das ist eine reichlich naive (oder ziemlich arrogante) Sichtweise.

> > Manchmal sind Abstraktionen der bessere Weg.

> Das halte ich für «debatable». Weniger Komplexität ist der bessere
> Weg.

It depends?!

--
Stefan.

Georg Bauhaus

unread,
Jan 29, 2003, 7:30:27 AM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

: ['=' bedeutet?]
: Das ist alles herzlich irrlevant, denn es handelt sich bis auf den
: ersten um externe Faktoren (dh Gegenst?nde einer getrennten
: Betrachtung).

Fuer SPARK ist das genau nicht eine getrennte Betrachtung,
sondern wesentliches Kriterium. Ermoeglicht u.a. durch eine
entsprechend eingeschraenkte und ergaenzte Sprache.


:> Faellt es dir hier so leicht, sagen wir innerhalb von 2 min,


:> diese Angaben fuer einen Echtwelt-Wartungsfall zu machen?

: Es sollte.

Tat es mal?

:> Kommt drauf an. Wenn irgendwo long in einem C Programm steht,


:> ist damit noch nicht gesagt, welche Teilmenge von Zahlen in der
:> entsprechenden Groesse enthalten sein werden.

: F?r jede Implementierung schon. Gegen Fehlverwendung hilft das
: allerdings wenig.

Richtig, aber es ist moeglich
a/ Sprachen zu verwenden, die den Typ-Bereich zahlgenau angeben,
und pruefen,
b/ Teile der Implementierungs-Abhaengigkeiten im quellcode zu
behandeln, so das ein Implementierungs-Wechsel keine manuelle
Neuerstellung von Programmteilen erfordert.
c/ Sprachen/tools zu verwenden, die, an Z spezifikationen angelehnt,
versuchen, Fehlverwendungen zu verhindern,


:> (Assertions als Beispiel zur Explizitheit des semantischen


:> Inhalts eines Programms: Sie sind in einigen Sprachen
:> mehr, in anderen weniger explizit angebbar. Es sei denn du findest
:> es vorteilhaft, wenn die Programmierer, sagen wir die von dir
:> genannten "Engineers", diese Pruefungs-Anweisungen und deren Handling
:> repetitiv und explizit selbst schreiben, Mechanismen, die sonst in
:> Sprachen enthalten sind.)

: Kaum.

Wenn "kaum" sich auf "vorteilhaft finden" bezieht, kann ich davon
ausgehen, dass dir Vor/Nachbedingungen, (In)Varianten, als Sprach-
Bestandteil wuenschenswert erscheinen?

Gruesse,
Georg

Rainer Weikusat

unread,
Jan 29, 2003, 7:36:35 AM1/29/03
to
Stefan Nobis <ste...@snobis.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
> > > > Das «Verständnis» sagt per se gar nichts aus. Aber der Quelltext tut
> > > > das: Er ist eine vollständige Beschreibung dessen, was die Software
> > > > zur Laufzeit tun wird.
>
> > > Nein, diese Beschreibung ist mitnichten vollstaendig. Was tut das
> > > System, wenn die Software einen Zeiger dereferenziert, der auf ein
> > > zufaellig bereits freigegebenes Objekt zeigt?
>
> > Wie passiert das ohne im Quellcode auffindbar zu sein?
>
> Falsche Frage! Du hast behauptet, der Quelltext sei eine
> *vollständige* Beschreibung dess, was die Software zur Laufzeit tun
> wird. Was also tut die Software bei einem solchen Fehler?

Sie enthält ihn. Wahlweise bekomme ich eine exception, überschreibe
die Interruptvektorentabelle, erhälte den Wert 0 etc pp.

> Du kannst das nicht ausschließlich aus dem Quelltext heraus
> beantworten, weil du die exakte Semantik bestimmter

> Bibliotheksfunktionen kennen musst. Richtig. Also kann der Quelltext


> keine *vollständige* Beschreibung des Laufzeitverhaltens sein.

Er enthält keine vollständige Beschreibung aller konkreten Ereignisse,
die das Programm auslösen kann. Das ist aber nicht dasselbe.

> > > Und *Du* kannst bei 100KSLOC *garantieren*, dass keiner dieser Fehler
> > > auftritt?
>
> > Spielt das eine wesentliche Rolle, falls man das muß?
>
> Wenn ein solcher Fehler u.U. Menschenleben kosten kann, spielt es eine
> sehr große Rolle, ob du die Fehlerfreiheit garantieren kannst.

Suche bitte via google nach 'Therac-25' für einen kurzen Überblick,
welche Todesfolgen durch software malfunction den (US-amerikanischen)
Regulierungsbehörden anscheinend noch genügen, bloß Nachbesserungen zu
fordern.

> > Das ist die falsche Frage. «Wie lange dauert es, bis 1000 Zeilen Code
> > fehlerfrei sind?»
>
> Nein, du stellst hier die falsche Frage. Woher weißt du, dass in
> deinem Quelltext keine weiteren Fehler sind?

Nein, die Frage wäre, woher *Du* das wissen kannst, falls die Quellen
von mir sind.

> Wagst du es wirklich, Software für kritische Systeme zu schreiben
> und für jeden auftretenden Fehler persönlich zu haften?

Dafür, daß keine Katastrophen stattfinden in jedem Fall bzw dafür, daß
dokumentiert ist, welche Katastropen stattfinden könnten.

> Wenn jemals in einem der von dir geschriebenen Programme ein Fehler
> auftauchte/gefunden wurde, nachdem du das Programm für den
> Produktionsbetrieb freigegeben hattest, solltest du ganz schnell mal
> von deinem hohen Ross 'runterkommen.

Der letzte, an den ich mich erinnern könnte, der nicht aufgrund
unbekannter externer Faktoren auftrat, wie Fehlfunktionen anderer
Programme, liegt schon ein paar Jährchen zurück.

NB: Irgendwelche Dinge, die ich ggf mit labels wie 'alpha' oder 'beta'
veröffentliche, gehören da nicht dazu.

> > > Ein formale Beschreibung, deren Konsistenz Du bitte
> > > *wie* nachweist?
>
> > Wem gegenüber?
>
> Den Angehörigen des Opfers deiner Fehler... und dem Staatsanwalt, der
> dich wegen fahrlässiger Tötung anklagt.

Beide sind nicht qualifiziert, einen solchen Nachweis zu verstehen,
obwohl sie das lernen könnten (Faustregel: Wer etwas nicht
grundsätzlich allgemeinverständlich erklären kann, hat auch keinen Durchblick).

> > Bitte? «Man kann keine Algorithmen schreiben, deren Speicherverbrauch
> > über die vollständige Laufzeit O(1) ist?», sagen wir mal trivial
> > dadurch, daß man eine maximale Anzahl an mallocs durchführt und die
> > allozierten Objekte weiterverwendet. Das gibt dann eine Invariante,
>
> Und? Damit hast du effektiv eine statische Speicherverwaltung und der
> Kern der dynamischen Speicherverwaltung, nämlich die
> Unvorhersehbarkeit des notwendigen Speichers, bleibt außen vor.

Nein, damit habe ich effektiv eine Speicherverwaltung, die im
Rahmen konstanter Limits operiert.

> Dann kann man aber eigentlich auch gleich auf die mallocs
> verzichten. :)
>
> > Sprachen geschrieben werden, die die verwantwortlichen Autoren auch
> > beherrschen. Solche Anforderungen sind für Übersetzer(!!)
>
> Wobei du unter "beherrschen" offensichtlich verstehst, dass man keine
> Fehler macht (die man nicht trivial in ein paar Stunden debugging
> garantiert findet und eliminiert).

Man kann Programme so schreiben, daß das geht, wenn man sich selber
auf die Finger haut, bevor das der Compiler tut.

> > > Manchmal sind Abstraktionen der bessere Weg.
>
> > Das halte ich für «debatable». Weniger Komplexität ist der bessere
> > Weg.
>
> It depends?!

Dem würde ich nicht zustimmen: Ich halte eine simplere Lösung immer
für besser (wohlgemerkt: eine Lösung, keine Annäherung).

Rainer Weikusat

unread,
Jan 29, 2003, 7:54:27 AM1/29/03
to
Stefan Nobis <ste...@snobis.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
> > Stefan Nobis <ste...@snobis.de> writes:
> > > Rainer Weikusat <weik...@students.uni-mainz.de> writes:
> > > > Das «Verständnis» sagt per se gar nichts aus. Aber der Quelltext tut
> > > > das: Er ist eine vollständige Beschreibung dessen, was die Software zur
> > > > Laufzeit tun wird.
>
> > > Davon träumst du, oder?
>
> > Eine nichtdeterministische Maschine kann ich auch «formal» nicht
> > «verifizieren». Das sich praktische Vorteile dadurch ergeben, daß die
> > Semantik unter der Annahme einer deterministischen Maschine bekannt
> > und sinnvoll ist, sollte nachvollziehbar sein.
>
> Es wäre schön, wenn du, mal zur Abwechslung, auf die Kernaussagen
> eingehen könntest, statt wahllos themenflucht zu begehen.
>
> Wieso schafelst du von nichtdeterministischen Maschinen? Was tut das
> zur Sache? Es geht um konkrete, deterministische Rechner, reale
> Computer mit Betriebssystemen, vielen Bibliotheken, Laufzeitumgebung
> der verwendeten Programmiersprache etc.
>
> Und in diesem Kontext ist der Quelltext eben gerade keine
> *vollständige* Beschreibung dessen, was die Software zur Laufzeit
> tut,

Doch. Falls da drinsteht 'Software macht syscall #6 mit folgenden
Argumenten .. .. ..', dann tut sie genau das. 'man abstraction'.

> > > Wenn es um kritische Systeme geht, kann man getrost davon ausgehen,
> > > dass *kein* einziger Mensch jemals korrekten, sprich 100%
> > > fehlerfreien, Code schreibt.
>
> > Gründet sich die Annahme, daß die Mehrzahl aller «kritischen» Systeme
> > mehr oder minder irreparabel kaputt ist, eigentlich auf praktische
> > Erfahrungen? Gruselig ...
>
> Ich schrieb, dass kein Mensch 100% fehlerfreien Code zu schreiben in
> der Lage ist. Das Gegenteil müsstest du mir erstmal beweisen, da es
> diverse Studien gibt, die empirisch nachgewiesen haben, dass ab
> ca. 30.000 bis 50.000 Zeilen Quelltext garantiert eine gewisse
> Mindestzahl an Fehlern vorhanden ist.

Eine Statistik ohne statistisch abgesicherte Datenbasis ist Müll.

> Und solche Fehler eliminiert man eben nur mit sehr aufwendigen (und
> leider teuren) Verfahren. Das Genie, dass nur mit Texteditor und
> Compiler bewaffnet ohne weitere (technische) Hilfsmittel (von Doku mal
> abgesehen :)), fehlerfreie Systeme mit mehreren zehntausend Zeilen
> Quelltext erstellen kann, musst du mir echt mal zeigen.

Das ist eine Frage des investierten Zeitaufwandes.

> > «Die Achterbahn des Schreckens, Teil II». Ist Dir klar, das jede
> > automatisch verhinderte «Fehlerklasse» ein weiterer kludge ist, der
> > um einen mittlerweile bekannten möglichen Fehler herumwürgt?
>
> Könntest du das mal näher ausführen? Ich verstehe nicht, was du
> meinst.

Woher nimmst Du die Gewissheit, daß die Menge möglicher
'Fehlerklassen' endlich ist?

> Oder spielst du darauf an: Mensch kennt ja die möglichen
> Fehlerquellen, also sollte es kein Problem sein, die Fehler zu
> vermeiden.

IdR ist es das auch nicht. Kannst Du Dir vorstellen, warum man
Handwerker drei Jahre lang systematisch üben läßt? Wer tut das bei
Programmierern nach Maßgabe welcher Voraussetzungen?

> Und du hast ja auch noch nie in deinem Leben einen Fehler ein zweites
> Mal begangen, gelle.
>
> Mal konkret: Wie stellst du dir eigentlich die Entwicklung von
> z.B. der Steuer-Software der Ariane vor?

"100 Millionen dressierte Affen".

> Auf die Genialität der Programmierer hoffen,

Herrgott ...

"[...] das Genie, das ausgebildete Kunsttalen, [...]"
(JWG)

> > > Aber auf einem völlig anderen Abstraktionsniveau. Auf diese Weise
> > > bekomme ich etliche neue Fehlerquellen.
>
> > Zwischenschritt eliminieren ;-).
>
> Abstraktions- und Kontrollebenen eliminiert. Für die Entwicklung eines
> sicheren und robusten LDAP-Servers wahrscheinlich sinnvoll, für obiges
> Beispiel der Ariane-Steuerung, zumal bei großen Teams mit den dabei
> auftretendem Kommunikationsoverhead und -problemen, halte ich es für
> ein sehr großes Problem, diese Zwischenschritte zu eliminieren.

Dann bekommt man potentielle Übersetzungfehler. Ob das problematisch
ist, spielt absolut keine Rolle.

> Diese Zwischenschritte erlauben in einem (größeren) Team eine bessere
> Kommunikation, da durch eine gemeinsame, formalisierte Sprache erstmal
> dafür gesorgt wird, dass auch wirklich alle von derselben Sache
> sprechen und dasselbe meinen. Die Quelltextebene wäre hier (bei
> komplexen Systemen und größeren Teams) zu sehr mit Details belastet,
> so dass der Blick für das Wesentliche zu schnell verloren geht.

Dann ist das ein starkes Indiz dafür, daß der Quelltext Müll ist.

> > > > C-Programme beschreiben normalerweise Registermaschinen.
>
> > > So ein Quark. C basiert noch nicht einmal auf einer klaren
>
> > Offensichtlich kann man jedes Programm in einer imperativen
> > Programmiersprache auch als spezialisierten IC realisieren. Ein
> > Programm ist eine virtuelle Maschine, die auf einer etwas
> > allgemeineren simuliert wird.
>
> Eine Registermaschine ist ein klar definierter Begriff. Und eine
> solche Registermaschine wird durch kein C Programm beschrieben (man
> kann aber C Programme in Programme für Registermaschinen
> übersetzen).
>
> Buzzwords und schwammige Ausdrucksweisen helfen dir da nicht weiter.

Mich beschleicht eher das Gefühl, es wäre sinnlos, mit Leuten zu
diskutieren, denen so elementare Konzepte nicht vertraut sind.

> Und um in deinem Begriffswirrwarr zu bleiben: Dadurch, dass VM A auf
> VM B simuliert wird, ist VM A nicht gleich eine Beschreibung von VM
> B.

Eine grandios sinnlose Aussage. Bitte behaupte nicht, die wäre von
mir.

> Bleibt nur die Frage wie viele solcher Genies es gibt, die fehlerfrei
> programmieren können. Ob die Anzahl reicht, um den realen Bedarf an
> Software zu decken? Ich habe da so meine Zweifel.

Weil vor jedem Computer einer sitzt, der sich nicht damit auskennt,
und alle anderen deswegen wegbeißt, weil er dafür toll den Chef
belabern kann (der auch keinen Plan von der Materie hat) handelt es
sich um eine vollkommen hypothetische Fragestellung: Niemand würde so
jemanden jemals ein Programm schreiben lassen.

> > > Wieso sind einige Abstraktionskonzepte, wie Rekursionen u.a., wichtig
> > > und gut und andere wieder völlig überflüssig und böse?
>
> > Ich hatte nichts von «überflüssig» oder «böse» geschrieben.
>
> Nicht wörtlich, aber deine Aussagen suggerierten dies.

Dein Problem.

> > > Um Fehlerquellen zu vermeiden. Mit Adressen, zumal ihrer
> > > Repräsentation(!) in C, kann man rechnen,
>
> > Das ist bei Werten so üblich.
>
> Bei Konstanten nicht.

Ach, die Summe zweier Konstanter Zahlen ist nicht berechenbar?

> > > mit Referenzen (einer anderen Repräsentation) kann man nicht rechnen
> > > -- damit sind wilde Zeiger z.B. (nahezu) unmöglich.
>
> > Das hat nichts mit «Rechnen» zu tun, sondern damit, ob die abstrakte
> > Maschine, die von der Sprache beschrieben wird, Referenzen mit
> > beliebigen Werten gestattet.
>
> Nein, das hat damit zu tun, dass der Ausdruck "Referenz"
> i.a. impliziert, dass es sich um etwas relativ konstantes handelt,
> d.h. man kann immer nur ein existierendes Objekt referenzieren und
> nicht eine beliebige Speicheradresse (es sei denn, diese wäre ein
> zulässiges Objekt, was jedoch in den meisten Sprachen, die solche
> Abstraktionskonzepte bieten, nicht der Fall ist).
>
> Referenzen können also sehr wohl beliebige Werte annehmen, jedoch muss
> dieser Wert zu einem exitierenden, gültigen (dereferenzierbaren)
> Objekt gehören.

Also können sie *keine* beliebigen Werte annehmen.

Stefan Nobis

unread,
Jan 29, 2003, 8:29:52 AM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> > Du kannst das nicht ausschließlich aus dem Quelltext heraus
> > beantworten, weil du die exakte Semantik bestimmter
> > Bibliotheksfunktionen kennen musst. Richtig. Also kann der Quelltext
> > keine *vollständige* Beschreibung des Laufzeitverhaltens sein.

> Er enthält keine vollständige Beschreibung aller konkreten Ereignisse,
> die das Programm auslösen kann. Das ist aber nicht dasselbe.

Das Laufzeitverhalten ist per Definitionem die Menge der Ereignisse
und Abläufe, die das Programm zur Laufzeit auslöst. Eine
*vollständige* Beschreibung des Laufzeitverhaltens würde also per
Definitionem alle konkreten Ereignisse, die das Programm auslösen kann
bzw. tatsächlich auslösen wird, enthalten.

Alles andere ist keine *vollständige* Beschreibung des
Laufzeitverhaltens, von dem du die ganze Zeit sprichst. Und damit kann
der Quelltext auch niemals die alleinige Quelle zum
Programmverständnis sein.

Das ist der wesentliche Unterschied zwischen einem (statischen) Programm
und einem (dynamischen) Prozess. Das ist einer der Unterschiede, der
komplexe Systeme so schwer beherrschbar macht.

> > > Das ist die falsche Frage. «Wie lange dauert es, bis 1000 Zeilen Code
> > > fehlerfrei sind?»

> > Nein, du stellst hier die falsche Frage. Woher weißt du, dass in
> > deinem Quelltext keine weiteren Fehler sind?

> Nein, die Frage wäre, woher *Du* das wissen kannst, falls die Quellen
> von mir sind.

Ganz einfach: Ein von dir nicht entdeckter Fehler tritt bei mir auf.

Nicht, dass wir uns jetzt falsch verstehen. Formale Methoden können
natürlich genauso wenig garantieren, dass ein Quelltext völlig
fehlerfrei ist. Sie stellen aber eine *nachvollziehbare* und
*reproduzierbare* Methode der Verifikation dar, die über "ich traue
Herrn X zu, nahezu fehlerfreien Quelltext zu produzieren" hinaus
gehen.

> > > Bitte? «Man kann keine Algorithmen schreiben, deren Speicherverbrauch
> > > über die vollständige Laufzeit O(1) ist?», sagen wir mal trivial
> > > dadurch, daß man eine maximale Anzahl an mallocs durchführt und die
> > > allozierten Objekte weiterverwendet. Das gibt dann eine Invariante,

> > Und? Damit hast du effektiv eine statische Speicherverwaltung und der
> > Kern der dynamischen Speicherverwaltung, nämlich die
> > Unvorhersehbarkeit des notwendigen Speichers, bleibt außen vor.

> Nein, damit habe ich effektiv eine Speicherverwaltung, die im
> Rahmen konstanter Limits operiert.

Speicherverbrauch O(1) heißst konstanter Speicherverbrauch, d.h. man
kann sich problemlos ein mal am Anfang des Programm einen
Speicherblock besorgen (egal ob als Array oder per malloc oder wie
auch immer) und kommt damit für den Rest des Programms aus. Nicht
gerade etwas, was ich als wesentliches Merkmal einer dynamischen
Speicherverwaltung sehen würde.

> > Wobei du unter "beherrschen" offensichtlich verstehst, dass man keine
> > Fehler macht (die man nicht trivial in ein paar Stunden debugging
> > garantiert findet und eliminiert).

> Man kann Programme so schreiben, daß das geht, wenn man sich selber
> auf die Finger haut, bevor das der Compiler tut.

Und genau das halte ich für eine naive/fatale Fehleinschätzung der Art
und Weise, wie Menschen denken und wie sie Fehler machen. Ein
wesentlicher Punkt, der empirisch nachweisbar ist, lautet, dass
Menschen i.a. ihre eigenen Fehler nicht erkennen können (vielleicht
gelegentlich, vielleicht sogar oft, aber garantiert nicht immer).

Ein absolutes Wesensmerkmal von Menschen ist das Begehen von Fehlern
und ihre Schwierigkeit, eigene Fehler zu finden -- das hat mit der
Funktionsweise unseres Gehirns zu tun und ist nun mal nicht einfach so
abstellbar.

Formale Methoden sind hier einfach ein (vielleicht behäbiges und
umständliches, aber doch funktionierendes) Hilfsmittel, diesem
grundlegendes Umstand Rechnung zu tragen.

> Dem würde ich nicht zustimmen: Ich halte eine simplere Lösung immer
> für besser (wohlgemerkt: eine Lösung, keine Annäherung).

Nur manchmal ist die simpelste Lösung schon so komplex, dass sie ohne
Hilfe von mehrstufigen Abstraktionen kaum beherrschbar ist. Nicht
alles lässt sich (problemlos) in kleine Minimodule/-probleme
zerlegen.

--
Stefan.

Rainer Weikusat

unread,
Jan 29, 2003, 8:42:28 AM1/29/03
to
Stefan Nobis <ste...@snobis.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
> > > Du kannst das nicht ausschließlich aus dem Quelltext heraus
> > > beantworten, weil du die exakte Semantik bestimmter
> > > Bibliotheksfunktionen kennen musst. Richtig. Also kann der Quelltext
> > > keine *vollständige* Beschreibung des Laufzeitverhaltens sein.
>
> > Er enthält keine vollständige Beschreibung aller konkreten Ereignisse,
> > die das Programm auslösen kann. Das ist aber nicht dasselbe.
>
> Das Laufzeitverhalten ist per Definitionem die Menge der Ereignisse
> und Abläufe, die das Programm zur Laufzeit auslöst. Eine
> *vollständige* Beschreibung des Laufzeitverhaltens würde also per
> Definitionem alle konkreten Ereignisse, die das Programm auslösen kann
> bzw. tatsächlich auslösen wird, enthalten.
>
> Alles andere ist keine *vollständige* Beschreibung des
> Laufzeitverhaltens, von dem du die ganze Zeit sprichst. Und damit kann
> der Quelltext auch niemals die alleinige Quelle zum
> Programmverständnis sein.

Was ein abstruser Schwachsinn ...

> Das ist der wesentliche Unterschied zwischen einem (statischen)
> Programm und einem (dynamischen) Prozess. Das ist einer der
> Unterschiede, der komplexe Systeme so schwer beherrschbar macht.

Konsequente Realitätsverneinung macht 'komplexe Systeme'
unbeherrschbar.

> > > > Das ist die falsche Frage. «Wie lange dauert es, bis 1000 Zeilen Code
> > > > fehlerfrei sind?»
>
> > > Nein, du stellst hier die falsche Frage. Woher weißt du, dass in
> > > deinem Quelltext keine weiteren Fehler sind?
>
> > Nein, die Frage wäre, woher *Du* das wissen kannst, falls die Quellen
> > von mir sind.
>
> Ganz einfach: Ein von dir nicht entdeckter Fehler tritt bei mir auf.

Daher weißt Du, das ich keine Fehler gemacht hatte? Interessant.
"Danach bewies der Mensch weil es so schön war noch, daß Schwarz
gleich Weiß sei und kam auf dem nächsten Zebrastreifen unter die
Räder".

> Nicht, dass wir uns jetzt falsch verstehen. Formale Methoden können
> natürlich genauso wenig garantieren, dass ein Quelltext völlig
> fehlerfrei ist. Sie stellen aber eine *nachvollziehbare* und
> *reproduzierbare* Methode der Verifikation dar, die über "ich traue
> Herrn X zu, nahezu fehlerfreien Quelltext zu produzieren" hinaus
> gehen.

Da der Quelltext Deiner Argumentation nach für das Verhalten des
Systems letztendlich irrelevant ist, warum fühlst Du Dich besser, wenn
Du Herrn X vertraust, der beliebige Aussagen darüber macht, die Du
nicht nachprüfst?

> > > Und? Damit hast du effektiv eine statische Speicherverwaltung und der
> > > Kern der dynamischen Speicherverwaltung, nämlich die
> > > Unvorhersehbarkeit des notwendigen Speichers, bleibt außen vor.
>
> > Nein, damit habe ich effektiv eine Speicherverwaltung, die im
> > Rahmen konstanter Limits operiert.
>
> Speicherverbrauch O(1) heißst konstanter Speicherverbrauch, d.h. man
> kann sich problemlos ein mal am Anfang des Programm einen
> Speicherblock besorgen (egal ob als Array oder per malloc oder wie
> auch immer) und kommt damit für den Rest des Programms aus.

Nein, denn eine konstante Obergrenze muß weder bekannt noch trivial
ermittelbar sein.

> > > Wobei du unter "beherrschen" offensichtlich verstehst, dass man keine
> > > Fehler macht (die man nicht trivial in ein paar Stunden debugging
> > > garantiert findet und eliminiert).
>
> > Man kann Programme so schreiben, daß das geht, wenn man sich selber
> > auf die Finger haut, bevor das der Compiler tut.
>
> Und genau das halte ich für eine naive/fatale Fehleinschätzung der Art
> und Weise, wie Menschen denken und wie sie Fehler machen. Ein
> wesentlicher Punkt, der empirisch nachweisbar ist, lautet, dass
> Menschen i.a. ihre eigenen Fehler nicht erkennen können (vielleicht
> gelegentlich, vielleicht sogar oft, aber garantiert nicht immer).
>
> Ein absolutes Wesensmerkmal von Menschen ist das Begehen von Fehlern
> und ihre Schwierigkeit, eigene Fehler zu finden -- das hat mit der
> Funktionsweise unseres Gehirns zu tun und ist nun mal nicht einfach so
> abstellbar.

Das ist eine küchenpsychologische Pseudobegründung für vollkommenen
Unfug.

> > Dem würde ich nicht zustimmen: Ich halte eine simplere Lösung immer
> > für besser (wohlgemerkt: eine Lösung, keine Annäherung).
>
> Nur manchmal ist die simpelste Lösung schon so komplex, dass sie ohne
> Hilfe von mehrstufigen Abstraktionen kaum beherrschbar ist. Nicht
> alles lässt sich (problemlos) in kleine Minimodule/-probleme
> zerlegen.

Offensichtlich widerspricht die erste Hälfte des Satzes der
zweiten. Make up your mind.

Stefan Nobis

unread,
Jan 29, 2003, 8:54:24 AM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> > Und in diesem Kontext ist der Quelltext eben gerade keine
> > *vollständige* Beschreibung dessen, was die Software zur Laufzeit
> > tut,

> Doch. Falls da drinsteht 'Software macht syscall #6 mit folgenden
> Argumenten .. .. ..', dann tut sie genau das. 'man abstraction'.

Wie schon im anderen Posting: Das *Laufzeitverhalten* ist mehr. Dazu
gehört auch die Semantik des syscall. Das hat nichts mit Abstraktion,
sondern nur mit der üblichen Definition des Begriffs Laufzeitverhalten
zu tun.

Wenn du natürlich einfach übliche Begriffe nach deinem Gutdünken
umdefinierst, darfst du dich über Missverständnisse nicht wundern.

> Woher nimmst Du die Gewissheit, daß die Menge möglicher
> 'Fehlerklassen' endlich ist?

Ganz einfach: Menschen können nur eine endliche Zahl von Aktionen (in
ihrem Leben) durchführen. Damit können sie auch nur eine endliche Zahl
von Fehlern machen. Auch alle Menschen auf der Welt sind nur eine
endliche Zahl von Menschen, die insgesamt wieder nur eine endliche
Zahl von Fehlern machen können.

Die Anzahl der Fehlerklassen ist kleiner oder gleich aller möglichen
Fehler, deren Anzahl wiederum endlich ist. Also ist die Zahl aler
möglichen Fehlerklassen auch endlich.

Und davon mal abgesehen ging es um die Reduzierung von
Fehlerklassen. Dabei ist es prinzipiell erstmal unerheblich, wieviele
Fehlerklassen es ingesamt geben mag.

> > Oder spielst du darauf an: Mensch kennt ja die möglichen
> > Fehlerquellen, also sollte es kein Problem sein, die Fehler zu
> > vermeiden.

> IdR ist es das auch nicht. Kannst Du Dir vorstellen, warum man
> Handwerker drei Jahre lang systematisch üben läßt? Wer tut das bei
> Programmierern nach Maßgabe welcher Voraussetzungen?

Und dann machen selbst erfahrene Handwerksmeister immer noch Fehler --
manchmal unterlaufen ihnen sogar typische Anfängerfehler. Gibt dir das
nicht zu denken? Oder tust du das einfach als "unfähiger Idiot" ab?

> > > > > C-Programme beschreiben normalerweise Registermaschinen.

> > > > So ein Quark. C basiert noch nicht einmal auf einer klaren

> > > Offensichtlich kann man jedes Programm in einer imperativen
> > > Programmiersprache auch als spezialisierten IC realisieren. Ein
> > > Programm ist eine virtuelle Maschine, die auf einer etwas
> > > allgemeineren simuliert wird.

[...]


> > Und um in deinem Begriffswirrwarr zu bleiben: Dadurch, dass VM A auf
> > VM B simuliert wird, ist VM A nicht gleich eine Beschreibung von VM
> > B.

> Eine grandios sinnlose Aussage. Bitte behaupte nicht, die wäre von
> mir.

Doch, genau das hast du geschrieben. Lies mal da oben: "Ein Programm


ist eine virtuelle Maschine, die auf einer etwas allgemeineren

simuliert wird." Ander formuliert: VM A wird auf VM B simuliert. Damit
wolltest du begründen, dass C Programme (-> VM A) Registermaschinen
(-> VM B) beschreiben.

Wer versteht jetzt also welche elementaren Konzepte nicht? Oder fällt
es dir einfach schwer, dich klar und deutlich auszudrücken? Vielleicht
reden wir ja die ganze Zeit aneinander vorbei?

--
Stefan.

Stefan Nobis

unread,
Jan 29, 2003, 9:09:52 AM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> > > > Nein, du stellst hier die falsche Frage. Woher weißt du, dass in
> > > > deinem Quelltext keine weiteren Fehler sind?

> > > Nein, die Frage wäre, woher *Du* das wissen kannst, falls die Quellen
> > > von mir sind.

> > Ganz einfach: Ein von dir nicht entdeckter Fehler tritt bei mir auf.

> Daher weißt Du, das ich keine Fehler gemacht hatte? Interessant.
> "Danach bewies der Mensch weil es so schön war noch, daß Schwarz
> gleich Weiß sei und kam auf dem nächsten Zebrastreifen unter die
> Räder".

Häh? Du hast wirklich Schwierigkeiten, dich klar auszudrücken scheint
mir. Deine Aussage "die Frage wäre, woher du das wissen kannst"
bezieht sich klar auf die von mir in den Raum gestellt Frage und
beinhaltet damit die Frage, woher ich wissen kann, dass in deinem
Quelltext keine weiteren Fehler sind.

Und darauf habe ich entsprechend geantwortet.

In kritischen Systemen möchtest du entweder jegliche Fehler
eliminieren (garantiert zu 100% ist das eigentlich unmöglich) oder
zumindest *nachweisen* (und zwar im Zweifelsfall im juristischen Sinne
und vor Gericht) können, dass du dein möglichstes getan hast, Fehler
zu vermeiden.

Dies ist wichtig für den in den meisten rechtsstaatlichen Systemen
üblichen Begriff von Schadensersatz und Haftung. Ein "ich bin gut und
weiß was ich tue" wird dich im Zweifelsfall kaum vor einer
Produkthaftungspflicht entbinden. Zertifizierungen nach einem
allgemein anerkannten Stand der Technik/Wissenschaft hingegen schon.

> > Nicht, dass wir uns jetzt falsch verstehen. Formale Methoden können
> > natürlich genauso wenig garantieren, dass ein Quelltext völlig
> > fehlerfrei ist. Sie stellen aber eine *nachvollziehbare* und
> > *reproduzierbare* Methode der Verifikation dar, die über "ich traue
> > Herrn X zu, nahezu fehlerfreien Quelltext zu produzieren" hinaus
> > gehen.

> Da der Quelltext Deiner Argumentation nach für das Verhalten des
> Systems letztendlich irrelevant ist, warum fühlst Du Dich besser, wenn
> Du Herrn X vertraust, der beliebige Aussagen darüber macht, die Du
> nicht nachprüfst?

Zum einen ist dein postulierter Umkehrschluss aus meinen Ausführungen
weder zulässig noch richtig. Der Quelltext ist nicht irrelevant
(sondern nur eben keine *vollständige* Beschreibung des
Laufzeitverhaltens -- dieser Umstand macht ihn nicht irrelevant; wer
setzt dir solch abstruse Flausen in den Kopf?).

Zudem möchte ich gerade Herrn X nicht (blind) trauen, sondern seine
Methoden und Anstrengungen, den Quelltext möglichst fehlerfrei zu
halten, nachprüfen können. Da du jegliche formale Methoden jenseits
simpler Quelltextbetrachtung ablehnst, ist eine solche Überprüfbarkeit
schwierig.

> > Ein absolutes Wesensmerkmal von Menschen ist das Begehen von Fehlern
> > und ihre Schwierigkeit, eigene Fehler zu finden -- das hat mit der
> > Funktionsweise unseres Gehirns zu tun und ist nun mal nicht einfach so
> > abstellbar.

> Das ist eine küchenpsychologische Pseudobegründung für vollkommenen
> Unfug.

Aha. Und außer solchen Diffamierungen kannst du deine Meinung sicher
auch noch sachlich begründen!?

--
Stefan.

Rainer Weikusat

unread,
Jan 29, 2003, 10:23:35 AM1/29/03
to
Stefan Nobis <ste...@snobis.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
> > > Und in diesem Kontext ist der Quelltext eben gerade keine
> > > *vollständige* Beschreibung dessen, was die Software zur Laufzeit
> > > tut,
>
> > Doch. Falls da drinsteht 'Software macht syscall #6 mit folgenden
> > Argumenten .. .. ..', dann tut sie genau das. 'man abstraction'.
>
> Wie schon im anderen Posting: Das *Laufzeitverhalten* ist mehr. Dazu
> gehört auch die Semantik des syscall. Das hat nichts mit Abstraktion,
> sondern nur mit der üblichen Definition des Begriffs Laufzeitverhalten
> zu tun.

Der syscall hat eine definierte Semantik und inwiefern die
seine Implementierung der genügt, ist eine vollkommen andere
Baustelle, dh für die Korrektheit des Programmes irrelevant.

> Wenn du natürlich einfach übliche Begriffe nach deinem Gutdünken
> umdefinierst,

Siehe oben.

> > Woher nimmst Du die Gewissheit, daß die Menge möglicher
> > 'Fehlerklassen' endlich ist?
>
> Ganz einfach: Menschen können nur eine endliche Zahl von Aktionen (in
> ihrem Leben) durchführen. Damit können sie auch nur eine endliche Zahl
> von Fehlern machen.

Eine beliebige Anzahl von Menschen kann eine beliebige Anzahl
von Fehlern machen.

> Auch alle Menschen auf der Welt sind nur eine
> endliche Zahl von Menschen, die insgesamt wieder nur eine endliche
> Zahl von Fehlern machen können.
>
> Die Anzahl der Fehlerklassen ist kleiner oder gleich aller möglichen
> Fehler, deren Anzahl wiederum endlich ist.

- lediglich für jeden beliebigen Zeitraum unquantifizierbar groß -

> Und davon mal abgesehen ging es um die Reduzierung von
> Fehlerklassen. Dabei ist es prinzipiell erstmal unerheblich, wieviele
> Fehlerklassen es ingesamt geben mag.

OIC: Fehlerfreie Programme sind zwar unmöglich, aber nicht solche,
die zuverlässig alle Fehler verhindern. Wieviel Widersprüche willst Du
noch auftürmen?

> > > Oder spielst du darauf an: Mensch kennt ja die möglichen
> > > Fehlerquellen, also sollte es kein Problem sein, die Fehler zu
> > > vermeiden.
>
> > IdR ist es das auch nicht. Kannst Du Dir vorstellen, warum man
> > Handwerker drei Jahre lang systematisch üben läßt? Wer tut das bei
> > Programmierern nach Maßgabe welcher Voraussetzungen?
>
> Und dann machen selbst erfahrene Handwerksmeister immer noch Fehler --
> manchmal unterlaufen ihnen sogar typische Anfängerfehler. Gibt dir das
> nicht zu denken?

Wir fordern also deswegen, jegliche Berufsausbildung wegen
Zwecklosigkeit abzuschaffen und alles weitere Maschinen zu
überlassen, die von unausgebildeten zusammengebaut wurden?

Wenn man euch so zuhört, könnte man es wirklich mit der Angst zu tun
kriegen.

> Oder tust du das einfach als "unfähiger Idiot" ab?

Diese Formulierung habe ich im kompletten Thread nicht nur nicht
verwendet, sondern ihrer Verwendung sogar nahezu jedesmal
widersprochen. Wie kommst Du zu der unglaublichen Frechheit,
wahrheitswidrig das Gegenteil zu behaupten?

> > > > Offensichtlich kann man jedes Programm in einer imperativen
> > > > Programmiersprache auch als spezialisierten IC realisieren. Ein
> > > > Programm ist eine virtuelle Maschine, die auf einer etwas
> > > > allgemeineren simuliert wird.
> [...]
> > > Und um in deinem Begriffswirrwarr zu bleiben: Dadurch, dass VM A auf
> > > VM B simuliert wird, ist VM A nicht gleich eine Beschreibung von VM
> > > B.
>
> > Eine grandios sinnlose Aussage. Bitte behaupte nicht, die wäre von
> > mir.
>
> Doch, genau das hast du geschrieben.

Was ich 'genau' geschrieben hatte, steht oben.

Rainer Weikusat

unread,
Jan 29, 2003, 10:34:06 AM1/29/03
to
Stefan Nobis <ste...@snobis.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
> > > > > Nein, du stellst hier die falsche Frage. Woher weißt du, dass in
> > > > > deinem Quelltext keine weiteren Fehler sind?
>
> > > > Nein, die Frage wäre, woher *Du* das wissen kannst, falls die Quellen
> > > > von mir sind.
>
> > > Ganz einfach: Ein von dir nicht entdeckter Fehler tritt bei mir auf.
>
> > Daher weißt Du, das ich keine Fehler gemacht hatte? Interessant.
> > "Danach bewies der Mensch weil es so schön war noch, daß Schwarz
> > gleich Weiß sei und kam auf dem nächsten Zebrastreifen unter die
> > Räder".
>
> Häh? Du hast wirklich Schwierigkeiten, dich klar auszudrücken scheint
> mir. Deine Aussage "die Frage wäre, woher du das wissen kannst"
> bezieht sich klar auf die von mir in den Raum gestellt Frage und
> beinhaltet damit die Frage, woher ich wissen kann, dass in deinem
> Quelltext keine weiteren Fehler sind.
>
> Und darauf habe ich entsprechend geantwortet.

Was wörtlich zu der Aussage führt, das Du deswegen von der
Fehlefreiheit eines Quelltextes weißt, weil Dir seine
Fehlerhaftigkeit bekannt ist.

> In kritischen Systemen möchtest du entweder jegliche Fehler
> eliminieren (garantiert zu 100% ist das eigentlich unmöglich)

Die einzig logische Schlußfolgerung ist, daß Computer unter keinen wie
auch immer gearteten Umständen lebenswichtige Aufgaben übernehmen
dürfen. Bitte richte Dich danach.

> Dies ist wichtig für den in den meisten rechtsstaatlichen Systemen
> üblichen Begriff von Schadensersatz und Haftung. Ein "ich bin gut und
> weiß was ich tue" wird dich im Zweifelsfall kaum vor einer
> Produkthaftungspflicht entbinden. Zertifizierungen nach einem
> allgemein anerkannten Stand der Technik/Wissenschaft hingegen schon.

OIC^2: Schlamperei mit Diplom => wunderbar, denn die Toten sind zwar tot,
aber es haftet keiner. Glückwunsch, 'Profi': Du hast das GmbH-Prinzip
verstanden.

> > > Nicht, dass wir uns jetzt falsch verstehen. Formale Methoden können
> > > natürlich genauso wenig garantieren, dass ein Quelltext völlig
> > > fehlerfrei ist. Sie stellen aber eine *nachvollziehbare* und
> > > *reproduzierbare* Methode der Verifikation dar, die über "ich traue
> > > Herrn X zu, nahezu fehlerfreien Quelltext zu produzieren" hinaus
> > > gehen.
>
> > Da der Quelltext Deiner Argumentation nach für das Verhalten des
> > Systems letztendlich irrelevant ist, warum fühlst Du Dich besser, wenn
> > Du Herrn X vertraust, der beliebige Aussagen darüber macht, die Du
> > nicht nachprüfst?
>
> Zum einen ist dein postulierter Umkehrschluss aus meinen Ausführungen
> weder zulässig noch richtig. Der Quelltext ist nicht irrelevant

Welche Relevanz besitzt er dann?

> Zudem möchte ich gerade Herrn X nicht (blind) trauen, sondern seine
> Methoden und Anstrengungen, den Quelltext möglichst fehlerfrei zu
> halten, nachprüfen können. Da du jegliche formale Methoden jenseits
> simpler Quelltextbetrachtung ablehnst, ist eine solche Überprüfbarkeit
> schwierig.

Wenn Du die 'formale Methode' selber aus den Quellen
herausdestillieren kannst, dann brauchst Du sie nicht, und andernfalls
mußt Du darauf vertrauen, daß derjenige, der das getan hat, die
Fähigkeiten besitzt, deren Existenz zu in Abrede stellst. Du gewinnst
also real nichts an Erkenntnis.

> > > Ein absolutes Wesensmerkmal von Menschen ist das Begehen von Fehlern
> > > und ihre Schwierigkeit, eigene Fehler zu finden -- das hat mit der
> > > Funktionsweise unseres Gehirns zu tun und ist nun mal nicht einfach so
> > > abstellbar.
>
> > Das ist eine küchenpsychologische Pseudobegründung für vollkommenen
> > Unfug.
>
> Aha. Und außer solchen Diffamierungen kannst du deine Meinung sicher
> auch noch sachlich begründen!?

Wozu?

Georg Bauhaus

unread,
Jan 29, 2003, 11:26:43 AM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

:> Und in diesem Kontext ist der Quelltext eben gerade keine
:> *vollst?ndige* Beschreibung dessen, was die Software zur Laufzeit
:> tut,

: Doch. Falls da drinsteht 'Software macht syscall #6 mit folgenden
: Argumenten .. .. ..', dann tut sie genau das. 'man abstraction'.

Nun bleibt davon auszugehen, dass syscall #6 (.. .. ..) sich genau
so verhaelt, rekusiv so verhaelt, wie der ein korrektes programm
schreibende Autor sich das vorstellen muss.

Was bedeutet Euer beider Meinung nach Laufzeit-Verhalten?
Gegeben int main(int a, char** A) { return a; },
ist damit das Laufzeitverhalten vollstaendig beschrieben?

Georg Bauhaus

unread,
Jan 29, 2003, 11:28:54 AM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

:> weil im


:> allgemeinen Fall fuer den Funktions-Aufruf stack-speicher, und
:> zwar in statisch nicht vorhersagbarer Menge, benoetigt werden wird.
:> Das ist hier entscheidend.

: Die Speichermenge, die ben?tigt wird, h?ngt von den Eingabedaten
: ab.

Und? Konstant oder Linear? SPARK schraenkt so ein dass der
Speicherverbrauch fuer _jede_ erlaubte Eingabe vorhersagbar
ist.

Vinzent Hoefler

unread,
Jan 29, 2003, 11:50:00 AM1/29/03
to
Rainer Weikusat wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Rainer Weikusat wrote:
>>
>> Eben. Aber Deinen Aussagen nach zu urteilen, die darauf schliessen
>> lassen, dass Du ausschliesslich dem "faehigen Programmierer"
>> vertraust, koennen Deine Massstaebe an Software nicht allzu hoch
>> sein.
>
> Du behauptest das ständig, obwohl ich fortwährend das Gegenteil
> schreibe.

Kommt mir absolut nicht so vor, da Du offensichtlich formale Methoden
ablehnst und Dir der Quelltext als Erkenntnis fuer das korrekte
Arbeiten des Programms offensichtlich vollkommen ausreichend erscheint.

>> > Das «Verständnis» sagt per se gar nichts aus. Aber der Quelltext
>> > tut das: Er ist eine vollständige Beschreibung dessen, was die
>> > Software zur Laufzeit tun wird.
>>
>> Nein, diese Beschreibung ist mitnichten vollstaendig. Was tut das
>> System, wenn die Software einen Zeiger dereferenziert, der auf ein
>> zufaellig bereits freigegebenes Objekt zeigt?
>
> Wie passiert das ohne im Quellcode auffindbar zu sein?

Wer sagt, dass das nicht auffindbar waere? Aber was am Quelltext
beschreibt nun, was da passiert? Ich lese da immer nur undefined
behaviour.

>> Was passiert, wenn mit den Ergebnissen aus uninitialisierten
>> Variablen gerechnet wird?
>
> Dann wird mit uninitialsierten Variablen gerechnet. Das konkrete
> Ergebnis ist falsch und somit egal.

Aber es ist im Source wohl kaum vollstaendig beschrieben.

>> Das ganze ist nicht einmal mehr deterministisch, was willst Du da
>> mit dem Source anfangen?
>
> Beides korrigieren. Warum?

Weil Du sagtest, der Source wuerde das Verhalten des System vollstaendig
beschreiben.

>> Und *Du* kannst bei 100KSLOC *garantieren*, dass keiner dieser Fehler
>> auftritt?
>
> Spielt das eine wesentliche Rolle, falls man das muß?

Sogar eine sehr wesentliche.

>> > Es ist möglich, eine 100.000-Zeilen-Programm so zu konstruieren,
>> > daß man keine Einheiten von mehr als maximal tausend Zeilen hat und
>> > so, daß diese Einheiten keine internen Abhängigkeiten haben.
>>
>> Ja. Was nicht heisst, dass es nachher funktioniert.
>
> Falls der Entwurf Müll war, bekommt man ein korrektes Programm, das
> Müll tut.

Auch. Aber auch ein korrekter Entwurf garantiert Dir nicht die
Fehlerfreiheit des Programms.

>> > Die Grundvoraussetung für das, was ich geschrieben hatte
>> > («Tolerabilität von fringe case-Fehlersituationen»), ist, daß das
>> > System deswegen nicht Amok läuft, was man durch einen geeigneten
>> > internen Aufbau sicherstellt.
>>
>> Und in SPARK durch den Beweis der Abwesenheit von Laufzeitfehlern
>> garantieren kann.
>
> Lies das bitte mal durch
>
> <URL:http://www.freesoft.org/CIE/RFC/1035/43.htm>
>
> und erkläre mir bitte danach, wie eine Überlaufprüfung

Es ging nicht um Ueberlaufpruefung, es ging um Laufzeitfehler.

> mir gegen data
> corruption, die aufgrund einer verpeilten Implementierung ohne das
> höchstwertige Bit im Offset auftritt, falls es für die befragte zone
> soviel secondaries gibt, daß in der addtional info section
> Rückverweise > 255 vorkommen.

Sorry, aber wenn Daten A durch eine verpeilte Implementierung so zu
Daten B mutiert werden, dass sie trotzdem noch als gueltig anerkannt
werden, dann hast Du auf *jedem* System Pech gehabt. Dann ist die
verpeilte Implementierung falsch.

Was wolltest Du damit sagen? Dass, wenn ich eine Fehlerklasse nicht
ausschliessen kann, es unsinnig ist, andere auszuschliessen?

>> >> It is easier to fit the specification to a program than vice
>> >> versa?
>> >
>> > Entweder das Programm ist eine Übersetzung der Spezifikation in
>> > eine andere Sprache oder Du hast einen schrecklichen Fehler
>> > gemacht, der sich auch mit 400t glue code im Nachhinein nicht mehr
>> > wird reparieren lassen.
>>
>> Sorry, entweder Du traeumst oder Du bist einer von denen, die immer
>> auf Anhieb korrekte, der Spezifikation entsprechende Software
>> schreiben koennen. Wieviele Fehler hast Du im Durchschnitt pro
>> Tausend Zeilen Code?
>
> Das ist die falsche Frage. «Wie lange dauert es, bis 1000 Zeilen Code
> fehlerfrei sind?»

Meinetwegen auch das. Wie lange dauert es also, bis Du die
durchschnittlich 10 Fehler ausgemerzt hast?

>> BTW, auch die Spezifikation kann falsch sein bzw. Inkonsistenzen
>> haben.
>
> Das ist dann allerdings Pech, aber auf einer anderen Ebene.

Richtig.

>> Beim MultOS-CA hat man 38 Fehler aus der Spezifikationsphase erst in
>> der Kodierphase gefunden und einen waehrend der Operation.
>
> Zuviele Details.

Irrtum, zu wenige. Ein Teil der Spezifikation war nachweislich nicht
eindeutig.

>> > und (zum 1000x): Ein Programm ist bereits eine formale
>> > Beschreibung.
>>
>> LOL
>>
>> Ein formale Beschreibung, deren Konsistenz Du bitte
>> *wie* nachweist?
>
> Wem gegenüber?

Deinem Gewissen.

>> > Bei allen Dingen, mit denen ich praktisch zu tun habe, und dazu
>> > gehört Quellcode anderer Leute mit dazu, verhält sich das genau
>> > umgekehrt, dh der Code tut nicht das, was das Interface angeblich
>> > bereitstellt.
>>
>> Dann solltest Du die Leute grundsaetzlich wegen Unfaehigkeit feuern.
>
> Ich behelfe mir lieber damit, nichts wiederzuverwenden, was trivial
> reimplementierbar ist.

Toll. Klasse. Dein Nachfolger dann auch.

> Das, wovon Du redest, würde ich «design flaws» im Interface
> nennen.

Nein.

>> Ansonsten, steige bitte nie wieder in ein Flugzeug, vor allem nie
>> weider in eine Boeing. Das ist lebensgefaehrlich.
>
> Vermutlich. Aber das kürzlich für den häufigsten Luftfahrtunfall heißt
> «CIFT», was für «controlled flight into terrain» steht, dh der Pilot
> fliegt gegen den Berg und warum bleibt ein Geheimnis.

Niemand sagt, dass Software fehlerfrei waere. Angenommen, es waere ein
Softwarefehler, wuerdest Du sicher garantieren, dass die Software
korrekt waere, wenn Du sie geschrieben haettest?

>> Die Software haben nicht nur unfaehige Idioten geschrieben, die zu
>> bloed sind, Integer-Ueberlaeufe schon im Source zu erkennen,
>
> Wenn Du sie so nennen magst.

Das waren mehr oder weniger Deine Worte.

>> Brauche ich wirklich selten. Und in Embedded Systems- bzw.
>> Safety-Critical-Umgebungen will man das auch nicht. Es wird Dir in
>> den seltensten Faellen gelingen, nachzuweisen, dass Deine Techniken
>> nicht zu Speicherfragmentierung und/oder Memory-Leaks fuehren.
>
> Bitte? «Man kann keine Algorithmen schreiben, deren Speicherverbrauch
> über die vollständige Laufzeit O(1) ist?»,

Doch genau das kann man. Eben deshalb benoetigt man keine dynamische
Speicherverwaltung.

>> Auch deren Stackverbrauch, bevor die Runtime-Umgebung ein
>> Storage_Error ausloest (oder halt nicht)?
>
> In Abhängigkeit von den Eingabedaten. Klar. Wieso?

Das zeigst Du mir fuer eine beliebige Menge an Eingangsdaten. Wenn Du
fertig bist.

>> >> Eine Sprache, die es einfacher macht, korrekten Code zu schreiben,
>> >> weil das dann ja jedes Kind tun kann?
>> >
>> > Wie bereits erwähnt: Ich möchte nicht mein Leben einem Programm von
>> > jemandem anvertrauen, dem es «kompliziert» erscheint,
>> > integer-Überläufe im Quelltext sinnvoll zu behandeln
>>
>> Falls Du das auf mich beziehst:
>
> Ich halte Dich eigentlich nicht für ein Programm, lasse mich aber
> gerne eines besseren belehren.

*von jemandem*

>> > und der ein Spezialtool braucht, um potentielle zu finden.
>>
>> Wenn Du das so meinst. Demzufolge sollten sicherheitskritische
>> Programme in
>
> Sprachen geschrieben werden, die die verwantwortlichen Autoren auch
> beherrschen.

Auch. Im Idealfall. Was Dich nicht davon abhaelt, Fehler zu machen.

> Solche Anforderungen sind für Übersetzer(!!)
> selbstverständlich und die entwerfen keine «kritischen
> Systeme».

Aber auch diese machen Fehler.

>> > while (1)
>> > if (!*p) break;
>> > if (strcmp(*p, user->pw_name) == 0) {
>> > if (argv[1]) log_access(user->pw_name, argv
>> > + 1, argc - 1); goto found;
>> > }
>> >
>> > ++p;
>> > }
>> >
>> > setuid(uid);
>> > }
>> >
>> > found:

[...]


>>
>> for i in P'Range loop
>> if (P (i) = NULL) then
>> Set_UID (uid);
>> exit;
>> end if;
>>
>> if (P (i) = User.PW_Name) then
>> if (Argument (1) /= "") then
>> Log_Access (User.PW_Name, Argument (1), Argument_Count);
>> exit;
>> end if;
>> end if;
>> end loop;
>
> Das ist eine Schleife mit drei Abbruchbedingungen, von denen Du eine
> willkürlich im Schleifenkopf positioniert hast.

Oh, Du meinst, ein for (p = ...; *p; ++p) wuerde bei Dir etwas anderes
bedeuten?

> Ich halte das für eine
> Verwirrtaktik und brauchst wegen der Zählerei 'grundsätzlich' eine
> Überlaufprüfung.

Wo? Dort ist absolut keine Pruefung notwendig.

> Für den Wert gibt es möglicherweise eine konstante
> Obergröße, aber keine definierte Länge (... die nicht erst durch
> Zählen ermittelt werden müßte).

Das was Du dort benutzt hast, war ein Array auf irgendwelche Strukturen,
das habe ich auch genauso umgesetzt, ob Du dort nun Deinen Endemarker
drin hast oder nicht ist egal, denn das Array muss irgendwo eine fest
definierte Laenge haben.

>> > also wozu tun?
>>
>> Deswegen:
>>
>> |void something (char* blabla)
>>
>> vs.
>>
>> |procedure Something (BlaBla : in Char_Array);
>>
>> vs
>>
>> |procedure Something (Blabla : out Char_Array);
>>
>> Jetzt versuche mal, den drei Funktionen eine Nullzeiger zu uebergeben
>> und bei der C-Variante zu erzaehlen, ob blabla veraendert wird.
>>
>> Manchmal sind Abstraktionen der bessere Weg.
>
> Das halte ich für «debatable». Weniger Komplexität ist der bessere
> Weg.

Eben. Deswegen will man Pointer vermeiden. Sie fuehren zu komplexem
undurchschaubaren Code, der durch Abstraktion teilweise stark
vereinfacht werden kann. In obigen Beispiel weiss ich, dass ich darauf
vertrauen kann, das "in Char_Array" nicht veraendert wird und ich bei
"out Char_Array" den Parameter nicht vorher initialisieren muss. Was
ich nicht weiss ist, wie diese Parameter uebergeben werden, was mich
hier auch nicht interessiert. char* liefert mir die Informationen genau
andersherum.


Vinzent.

--
Mathematicians do it in theory.

Vinzent Hoefler

unread,
Jan 29, 2003, 11:56:16 AM1/29/03
to
Rainer Weikusat wrote:

> Eine Statistik ohne statistisch abgesicherte Datenbasis ist Müll.

Lies: http://www.adaic.com/whyada/ada-vs-c/cada_art.html

Eventuell ueberzeugt das ein wenig mehr, dass auch die Sprache einen
entscheidenden Anteil an der Fehlerzahl in Programmen haben kann.

>> Und solche Fehler eliminiert man eben nur mit sehr aufwendigen (und
>> leider teuren) Verfahren. Das Genie, dass nur mit Texteditor und
>> Compiler bewaffnet ohne weitere (technische) Hilfsmittel (von Doku
>> mal abgesehen :)), fehlerfreie Systeme mit mehreren zehntausend
>> Zeilen Quelltext erstellen kann, musst du mir echt mal zeigen.
>
> Das ist eine Frage des investierten Zeitaufwandes.

Und damit des Geldes, was andere nicht ausgeben wollen. Wie gesagt,
Lockheed-Martin meinten, dass sie durch den Einsatz von SPARK bei der
Entwicklung der C130J 80% der sonst ueblichen Entwicklungskosten fuer
die Software (einschliesslich Zertifikation) eingespart haetten. Leider
weigerte man sich, das genauer zu beziffern.

Warum zum Teufel soll ich Millionen verschwenden, wenn es anders (und
schneller) geht?

Sicher bekommst Du jedes Programm fehlerfrei. Irgendwann.

> IdR ist es das auch nicht. Kannst Du Dir vorstellen, warum man
> Handwerker drei Jahre lang systematisch üben läßt? Wer tut das bei
> Programmierern nach Maßgabe welcher Voraussetzungen?

Das hilft nicht. Du wirst besser, ja. Aber nie fehlerfrei.

>> Diese Zwischenschritte erlauben in einem (größeren) Team eine bessere
>> Kommunikation, da durch eine gemeinsame, formalisierte Sprache
>> erstmal dafür gesorgt wird, dass auch wirklich alle von derselben
>> Sache sprechen und dasselbe meinen. Die Quelltextebene wäre hier (bei
>> komplexen Systemen und größeren Teams) zu sehr mit Details belastet,
>> so dass der Blick für das Wesentliche zu schnell verloren geht.
>
> Dann ist das ein starkes Indiz dafür, daß der Quelltext Müll ist.

Dann ist wahrscheinlich so ziemlich jeder Quelltext, an dem mehr als ein
Programmierer sitzt, Muell.

>> > > Um Fehlerquellen zu vermeiden. Mit Adressen, zumal ihrer
>> > > Repräsentation(!) in C, kann man rechnen,
>>
>> > Das ist bei Werten so üblich.
>>
>> Bei Konstanten nicht.
>
> Ach, die Summe zweier Konstanter Zahlen ist nicht berechenbar?

Was genau noch mal ergibt die Summe zweier Adressen?


Vinzent.

Georg Bauhaus

unread,
Jan 29, 2003, 12:46:02 PM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

: Der syscall hat eine definierte Semantik und inwiefern die
: seine Implementierung der gen?gt, ist eine vollkommen andere
: Baustelle, dh f?r die Korrektheit des Programmes irrelevant.

Schon, und insofern arbeitet man, wenn nicht direkt mit CPU
und Zubehoer, immer mit dem Risiko, dass auch ein korrektes Programm
den Bach runter geht, wenn zB die Implementierung nicht stimmt.

Da hilft kein tool. (Auch nicht bei einer fehlerhaften FPU.)

Und? Ich glaube, das "hier" einige ihr Augenmerk auf dem
ausgefuehrten Programmcode haben, obwohl sie das nicht sagen,
wenn von Laufzeitverhalten die Rede ist.
Da ist es im Sinn der Spezifikation ueberhaupt nicht mehr
irrelevant, wenn zwar A's programm korrekt ist, aber B's
implementierung von syscall #6 nicht stimmt.

Es wird viel daran gearbeitet, korrekt arbeitende
Uebersetzer zu produzieren. SPARK geht in diese Richtung.

Ich glaube nicht, dass irgendeiner der tool-verfechter fehlerhafte
Bib-Funktionen oder kaputte Laufzeitsysteme ignorieren wuerde.

Wenn ein Programm genau dann als vollstaendig korrekt angesehen
wird, wenn jedes seiner Bestandteile als vollstaendig korrekt
angesehen werden konnte, usw, dann gibt es keinen falsch
implementierten syscall #6.

Wie waers damit?

Rainer Weikusat

unread,
Jan 29, 2003, 1:11:42 PM1/29/03
to
Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
>
> : ['=' bedeutet?]
> : Das ist alles herzlich irrlevant, denn es handelt sich bis auf den
> : ersten um externe Faktoren (dh Gegenst?nde einer getrennten
> : Betrachtung).
>
> Fuer SPARK ist das genau nicht eine getrennte Betrachtung,
> sondern wesentliches Kriterium.

Entweder Du akzeptierst die Semantik der Sprache, dann ist die
'Bedeutung' von = klar oder Du machst das nicht. Aber bitte ueberall,
egal wie rum.

> :> Faellt es dir hier so leicht, sagen wir innerhalb von 2 min,
> :> diese Angaben fuer einen Echtwelt-Wartungsfall zu machen?
>
> : Es sollte.
>
> Tat es mal?

Was sollen eigentlich die ganzen billigen rethorischen Tricks?
Du spekulierst vollkommen allgemein ueber
'Echtzeit-Wartungsfaelle'. Mehr als 'die sollten durchfuehrbar sein'
kann man dazu nicht sagen.

> :> Kommt drauf an. Wenn irgendwo long in einem C Programm steht,
> :> ist damit noch nicht gesagt, welche Teilmenge von Zahlen in der
> :> entsprechenden Groesse enthalten sein werden.
>
> : F?r jede Implementierung schon. Gegen Fehlverwendung hilft das
> : allerdings wenig.
>
> Richtig, aber es ist moeglich
> a/ Sprachen zu verwenden, die den Typ-Bereich zahlgenau angeben,

wie zB C.

> und pruefen,

Wozu will man das? Bestandteil der Eigenschaften endlicher Ganzahlen
ist, dass sie einen endlichen Wertebereich haben. Fuer Zahlen ohne
Vorzeichen ist ausserdem das Verhalten in so einem Fall definiert
(modulo 2^n mit n == sizeof(typ) * CHAR_BIT)), als Fehler kommt sowas
normalerweise nicht vor (ausser in Form von Eingabedaten, die
ungenuegend vor der Verarbeitung geprueft wurden) und in manchen
Faellen ist ein Ueberlauf sowohl unvermeidbar als auch Bestandteil der
normalen Operation des Systems (Sequenznummern beispielsweise).

Vor allem, warum sollte man das anstelle zuverlaessiger
Ganzahlarithmetik wollen, wenn man schon rechnen muss? Lisp hat
welche. Ada IIRC nicht.

> b/ Teile der Implementierungs-Abhaengigkeiten im quellcode zu
> behandeln, so das ein Implementierungs-Wechsel keine manuelle
> Neuerstellung von Programmteilen erfordert.

Im schlimmsten Fall erfordert sowas einen manuellen Austausch mehrerer
typedefs und sogar das ist schon laenger nicht mehr der Fall.

> c/ Sprachen/tools zu verwenden, die, an Z spezifikationen angelehnt,
> versuchen, Fehlverwendungen zu verhindern,

Wenn Du ein Tool brauchst, dass Dich daran hindert, 18-Bit-Werte in
8-Bit-Variablen zu speichern ist das schoen fuer Dich. Richtige
Programmfehler sind komplizierter.

> :> (Assertions als Beispiel zur Explizitheit des semantischen
> :> Inhalts eines Programms: Sie sind in einigen Sprachen
> :> mehr, in anderen weniger explizit angebbar. Es sei denn du findest
> :> es vorteilhaft, wenn die Programmierer, sagen wir die von dir
> :> genannten "Engineers", diese Pruefungs-Anweisungen und deren Handling
> :> repetitiv und explizit selbst schreiben, Mechanismen, die sonst in
> :> Sprachen enthalten sind.)
>
> : Kaum.
>
> Wenn "kaum" sich auf "vorteilhaft finden" bezieht, kann ich davon
> ausgehen, dass dir Vor/Nachbedingungen, (In)Varianten, als Sprach-
> Bestandteil wuenschenswert erscheinen?

Nein. Es erscheint mir wuenschenswert, dass Leute, die Programme
schreiben, mit solchen Begriffen vertraut sind und sie bei dieser
Taetigkeit 'nutzbringend' einsetzen. Das duerfte mehr Fehler im Ansatz
vermeiden, als ex post factum automatisch entdeckt werden koennen (da
alle Beteiligten ausser mir die Existenz fehlerfreier Programme
ausschliessen, sind alle genannten Verifkationsmethoden
erwiesenermassen sinnlos, ausser als Hilfsmittel). Der Rest ist
Werbung fuer ein kommerzielles Produkt einer Firma.

Stefan Nobis

unread,
Jan 29, 2003, 1:31:24 PM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> Wir fordern also deswegen, jegliche Berufsausbildung wegen
> Zwecklosigkeit abzuschaffen und alles weitere Maschinen zu
> überlassen, die von unausgebildeten zusammengebaut wurden?

Rainer, wenn du nicht bereit bist, zu lesen und sachlich zu
diskutieren, sag es -- ich habe mit meiner Zeit besseres zu tun, als
mich von dir verarschen zu lassen.

Für diesen Dummschwall deinerseits gibt's ein EOT meinerseits.

--
Stefan.

Stefan Nobis

unread,
Jan 29, 2003, 1:34:37 PM1/29/03
to
Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:

> Was bedeutet Euer beider Meinung nach Laufzeit-Verhalten?

Das Laufzeitverhalten ist das, was der durch ein Programm (nicht
vollständig) beschriebene Prozess tut.

> Gegeben int main(int a, char** A) { return a; },
> ist damit das Laufzeitverhalten vollstaendig beschrieben?

Natürlich kann bei obiger Definition ein Quelltext niemals das
Laufzeitverhalten vollständig beschreiben.

Und die Unterscheidung von Programm resp. dessen Quelltext und einem
laufenden Prozess, der das Programm ausführt, halte ich für wichtig.

--
Stefan.

Vinzent Hoefler

unread,
Jan 29, 2003, 2:26:25 PM1/29/03
to
Rainer Weikusat wrote:

> Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
>> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
>
>> :> Kommt drauf an. Wenn irgendwo long in einem C Programm steht,
>> :> ist damit noch nicht gesagt, welche Teilmenge von Zahlen in der
>> :> entsprechenden Groesse enthalten sein werden.
>>
>> : F?r jede Implementierung schon. Gegen Fehlverwendung hilft das
>> : allerdings wenig.
>>
>> Richtig, aber es ist moeglich
>> a/ Sprachen zu verwenden, die den Typ-Bereich zahlgenau angeben,
>
> wie zB C.

Wo sind in C Typen zahlgenau angegeben? In C ist fuer verschiedene Typen
ein Mindestbereich angegeben, den der Typ darstellen koennen muss, das
war's. Das sagst exakt nichts ueber die aktuelle Darstellbarkeit
darueber hinaus gehender Zahlen aus.

Aber bilde doch in C bitte mal zahlgenau folgendes ab:

type Timer is range 2 .. 65535;

> Wozu will man das? Bestandteil der Eigenschaften endlicher Ganzahlen
> ist, dass sie einen endlichen Wertebereich haben.

Richtig. Es ist aber eine unsinnige Idee, dieser Wertebereich sei
grundsaetzlich identisch mit dem durch die Archtektur ermoeglichten
Darstellungsbereich.

> Fuer Zahlen ohne
> Vorzeichen ist ausserdem das Verhalten in so einem Fall definiert
> (modulo 2^n mit n == sizeof(typ) * CHAR_BIT)),

Fuer unsigned Typen ist es ja offensichtlich nicht definiert, somit
kannst Du bei einem dort moeglichen Ueberlauf auch schon wieder nicht
sagen, was passiert.

> als Fehler kommt sowas normalerweise nicht vor

Komisch. Habe ich schon oft erlebt, in allen moeglichen und unmoeglichen
Varianten. Es koennte uebrigens sein, dass Du es einfach nur nicht
merkst.

In C reicht es schon, wenn Du mal vergisst, ein '\0' an einen String
anzuhaengen, um mit dem irgendeinem Index dann ausserhalb des
definierten (bzw. allozierten) Bereichs zuzugreifen. Und weil wir
gerade dabei sind: Wie genau ist das Verhalten von strlen () definiert,
wenn der String zur Laufzeit kein \0 enthaelt (und damit im Prinzip in
C kein String waere)?

> (ausser in Form von Eingabedaten, die
> ungenuegend vor der Verarbeitung geprueft wurden) und in manchen
> Faellen ist ein Ueberlauf sowohl unvermeidbar als auch Bestandteil der
> normalen Operation des Systems (Sequenznummern beispielsweise).
>
> Vor allem, warum sollte man das anstelle zuverlaessiger
> Ganzahlarithmetik wollen, wenn man schon rechnen muss? Lisp hat
> welche. Ada IIRC nicht.

Was hat Ada nicht? Ich kann Dir hier nicht ganz folgen. Modulare Typen,
d.h. also Typen, bei denen der Ueberlauf erlaubt und definiert ist, hat
Ada jedenfalls. Wenn es mit Spass macht, kann ich mir da sogar einen
modulo-13-Typen definieren.

Ganzzahlarithmetik ist uebrigens per se zuverlaessig, solange sie
innerhalb des definierten Bereichs bleibt.

>> c/ Sprachen/tools zu verwenden, die, an Z spezifikationen angelehnt,
>> versuchen, Fehlverwendungen zu verhindern,
>
> Wenn Du ein Tool brauchst, dass Dich daran hindert, 18-Bit-Werte in
> 8-Bit-Variablen zu speichern ist das schoen fuer Dich. Richtige
> Programmfehler sind komplizierter.

Unrichtige Programmfehler sind nicht weniger gefaehrlich. Eher im
Gegenteil, da meist schwerer erkennbar, weil sie oft nur bei ganz
bestimmten und seltenen Kombinationen von Eingangsdaten vorkommen.

>> Wenn "kaum" sich auf "vorteilhaft finden" bezieht, kann ich davon
>> ausgehen, dass dir Vor/Nachbedingungen, (In)Varianten, als Sprach-
>> Bestandteil wuenschenswert erscheinen?
>
> Nein. Es erscheint mir wuenschenswert, dass Leute, die Programme
> schreiben, mit solchen Begriffen vertraut sind und sie bei dieser
> Taetigkeit 'nutzbringend' einsetzen.

Genau das machst Du mit SPARK. Der einzige Unterschied ist, dass Dir
SPARK _bereits waehrend der Entwicklung_ statisch nachweist, dass Deine
Vor- und Nachbedingungen stimmen oder Du halt doch Laufzeitfehler
verursachen wuerdest, waehrend Du das sonst erst zur Laufzeit, also
*nach der Compilierung* pruefst oder darauf vertraust, dass auch jeder
im Team exakt die Spezifikationen seines Teils erfuellt und diese
Spezifikation korrekt ist.

> Das duerfte mehr Fehler im Ansatz
> vermeiden, als ex post factum automatisch entdeckt werden koennen

Ich kann kein Latein. Aber aus dem post (=nach) lese ich daraus mal
wieder, dass davon ausgehst, dass Du SPARK irgendwie im Nachhinein
verwendest und mir somit beweist, dass Du es tatsaechlich nicht
begriffen hast.

Ein SPARK-Programm wird genauso entwickelt, wie jedes andere auch,
ausser mit der zusaetzlichen Hilfe von Compiler (Examiner), der Dir
bereits in der Codierphase sagen kann, dass Du mit diesem Code
bestimmte Bedingungen, die Du vorgegeben hast, nicht erfuellst. Das ist
genauso *Bestandteil* der Sprache wie es pointer in C sind. SPARK ist
kein Tool, was man hinterher mal eben schnell einsetzt, um zu beweisen,
dass der Muell ja vielleicht doch korrekt ist.

Im Gegenteil, "trying to sparkify an existing program does not work".
Sagt Chapman.

Du musst von vornherein richtige Designentscheidungen treffen. Und
teilweise sogar wesentlich strengere als in anderen Sprachen, eben weil
es Dir sonst passieren kann, dass die Anzahl der zu beweisenden VCs
und/oder der von Dir anzugebenden Pre-/Postconditions ins unermessliche
waechst.

> (da
> alle Beteiligten ausser mir die Existenz fehlerfreier Programme
> ausschliessen,

Du glaubst tatsaechlich an die Existenz fehlerloser Programme?

> sind alle genannten Verifkationsmethoden
> erwiesenermassen sinnlos, ausser als Hilfsmittel).

SPARK ist eine Sprache. Insofern ist sie, wie jede andere
Programmiersprache auch, ein mehr oder minder gutes Hilfsmittel zum
Erstellen von Software.

> Der Rest ist
> Werbung fuer ein kommerzielles Produkt einer Firma.

Unsinn. C++ ist dann wohl auch ein kommerzielles Produkt, weil Microsoft
und andere einen Compiler verkaufen, der dies implementiert?

SPARK ist eine Sprache. Ein (bzw. der) SPARK-Examiner wird von Praxis
Critical Systems verkauft. Es steht Dir frei, einen eigenen zu
schreiben und dafuer Support zu leisten.


Vinzent.

--
He who findeth sensuous pleasures in the bodies of lush, hot, pink
damsels is not righteous, but he can have a lot more fun.

Rainer Weikusat

unread,
Jan 29, 2003, 4:45:34 PM1/29/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Rainer Weikusat wrote:
> > Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
> >> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
> >
> >> :> Kommt drauf an. Wenn irgendwo long in einem C Programm steht,
> >> :> ist damit noch nicht gesagt, welche Teilmenge von Zahlen in der
> >> :> entsprechenden Groesse enthalten sein werden.
> >>
> >> : F?r jede Implementierung schon. Gegen Fehlverwendung hilft das
> >> : allerdings wenig.
> >>
> >> Richtig, aber es ist moeglich
> >> a/ Sprachen zu verwenden, die den Typ-Bereich zahlgenau angeben,
> >
> > wie zB C.
>
> Wo sind in C Typen zahlgenau angegeben? In C ist fuer verschiedene Typen
> ein Mindestbereich angegeben, den der Typ darstellen koennen muss, das
> war's.

Du möchtest /usr/include/stdint.h durchlesen.

> Das sagst exakt nichts ueber die aktuelle Darstellbarkeit
> darueber hinaus gehender Zahlen aus.

Ach?

> Aber bilde doch in C bitte mal zahlgenau folgendes ab:
>
> type Timer is range 2 .. 65535;

Könntest Du vielleicht einen Algorithmus Deiner Wahl, der sowas
braucht, in eine Maschinensprache Deiner Wahl übersetzen und Du
bekommst dann eine C-Variante von mir davon, sobald ich dazu komme,
diese Sprache zu lernen? Außerdem will ich das nicht. Ich will
Maschinenworte benutzen, falls die nicht zu klein sind.

> > Wozu will man das? Bestandteil der Eigenschaften endlicher Ganzahlen
> > ist, dass sie einen endlichen Wertebereich haben.
>
> Richtig. Es ist aber eine unsinnige Idee, dieser Wertebereich sei
> grundsaetzlich identisch mit dem durch die Archtektur ermoeglichten
> Darstellungsbereich.

Es ist ein unsinniges Vorhaben, in dem Tempo, in dem sich die
mathematische Definition des Begriffes 'Zahl' ändert (sind 'wir' immer
noch bei 2d-Vektoren mit 'imaginärem Anteil'?), geeignete
Repräsentationen zu ersinnen.

> > als Fehler kommt sowas normalerweise nicht vor
>
> Komisch. Habe ich schon oft erlebt, in allen moeglichen und unmoeglichen
> Varianten. Es koennte uebrigens sein, dass Du es einfach nur nicht
> merkst.

Das könnte es. Es könnte im übrigen auch sein, daß ich ein großer,
rosafarbener Krake bin, der in einer psychatrischen Anstalt auf einem
Planeten in der Nähe von Alpha Centauri wegen hartnäckiger
Wahnvorstellungen ans Bett geschnallt werden muß. Ich bin noch damit
beschäftigt, beide Hypothesen hinsichtlich wünschenswürdiger
Konsequenzen zu bewerten.

> > Vor allem, warum sollte man das anstelle zuverlaessiger
> > Ganzahlarithmetik wollen, wenn man schon rechnen muss? Lisp hat
> > welche. Ada IIRC nicht.
>
> Was hat Ada nicht? Ich kann Dir hier nicht ganz folgen. Modulare Typen,
> d.h. also Typen, bei denen der Ueberlauf erlaubt und definiert ist, hat
> Ada jedenfalls. Wenn es mit Spass macht, kann ich mir da sogar einen
> modulo-13-Typen definieren.
>
> Ganzzahlarithmetik ist uebrigens per se zuverlaessig, solange sie
> innerhalb des definierten Bereichs bleibt.

Gehen sie sofort über Steele und nicht über Los.

> > Nein. Es erscheint mir wuenschenswert, dass Leute, die Programme
> > schreiben, mit solchen Begriffen vertraut sind und sie bei dieser
> > Taetigkeit 'nutzbringend' einsetzen.
>
> Genau das machst Du mit SPARK.

Und ohne.

Vinzent Hoefler

unread,
Jan 29, 2003, 7:39:12 PM1/29/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

>Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Rainer Weikusat wrote:
>>
>> Wo sind in C Typen zahlgenau angegeben? In C ist fuer verschiedene Typen
>> ein Mindestbereich angegeben, den der Typ darstellen koennen muss, das
>> war's.
>
>Du möchtest /usr/include/stdint.h durchlesen.

Wenn es auf meinem System denn vorhanden waere.

limits.h sagt mir jedenfalls gerade mal, welche Zahlenbereiche in den
momentan auf dem System verwendeten Typen darstellbar sind.

>> Das sagst exakt nichts ueber die aktuelle Darstellbarkeit
>> darueber hinaus gehender Zahlen aus.
>
>Ach?

Auf dem zufaellig aktuellen System magst Du dazu in der Lage sein.

>> Aber bilde doch in C bitte mal zahlgenau folgendes ab:
>>
>> type Timer is range 2 .. 65535;
>
>Könntest Du vielleicht einen Algorithmus Deiner Wahl, der sowas
>braucht, in eine Maschinensprache Deiner Wahl übersetzen und Du
>bekommst dann eine C-Variante von mir davon, sobald ich dazu komme,
>diese Sprache zu lernen?

Gee. Natuerlich wird es intern in passende Maschinenworte umgesetzt.

Trotzdem erlaubt mir das, simple Schleifen ueber den jeweiligen
Definitionsbereich des Typs auszufuehren, ohne dass ich mir
zusaetzliche Konstanten, die das weiterhin beschreiben und wo es dann
wieder in meiner Verantwortung liegt, die richtigen auszuwaehlen,
definieren muss:

|for i in Timer'Range loop ... end loop;

Das ist per definition korrekt. Warum sollte es zu weniger Fehlern
fuehren, wenn ich diese Abstraktion durch

for (int timer = TIMER_MIN; timer <= TIMER_MAX; timer++) {...}

selbst durchfuehren muss?

Desweiteren erlaubt mir der dadurch definierte Kontrakt, dass ich bei
folgendem:

|function Clamp_Timer_Value (Timer_Val : in float) return Timer;
|procedure Update_Timer (New_Timer : in Timer);

weder das Funktionsergebnis noch den Parameter auf eventuelle
Bereichsverletzungen pruefen muss. Eine Laufzeit-Exception wuerde mir
auch sicherstellen, dass ich niemals mit unsinnigen Werten
weiterrechne und dadurch moeglicherweise die Hardware in den Wind
schiesse.

Wenn ich das ganze noch in SPARK mache, kann mir das sogar
garantieren, dass Update_Timer *nie* mit ausserhalb des Bereichs
liegenden Parameter aufgerufen werden kann und somit auch kein
Laufzeitfehler auftreten kann. In C musst Du entweder explizite Checks
machen (idealerweise ueberall dort, wo Du das verwendest) und
entsprechend auf Verletzungen reagieren (= Laufzeitfehler) oder darauf
_vertrauen_, dass z.B. die Implementation von clamp_timer() auch
wirklich nur Werte zurueckgibt, die im erlaubten Bereich liegen.

Das ist dann entweder ineffizient oder (bzw. sogar *und*, falls Du den
Check irgendwo vergessen solltest) gefaehrlich.

>Außerdem will ich das nicht. Ich will
>Maschinenworte benutzen, falls die nicht zu klein sind.

Bitte:

|for Timer use 32;

Wo liegt Dein Problem? Wenn Du eine bestimmte Darstellung brauchst,
dann kannst Du das gern sagen.

Aber der Compiler ist ohnehin intelligent genug, fuer solche
Darstellungen die jeweils effizienteste Variante zu waehlen.

In C hingegen artet das meist in tollste #ifdef-Orgien aus, eben weil
der Compiler ja nicht weiss, was fuer Zahlen Du im Typen gerne
darstellen wuerdest. Also kann man, um portabel zu bleiben nicht immer
einfach einen int nehmen, sondern muss entweder via #ifdef (was auch
nicht gerade irgendeine Fehlerfreiheit garantiert) die jeweils beste
Variante auswaehlen oder eine moeglicherweise ineffizientere Variante
wie uint32 (oder wie das Teil auch immer heisst) benutzen.

Wie garantierst Du die jeweils effizienteste Darstellung o.g.
Zahlenbereiches in C?

>> > Wozu will man das? Bestandteil der Eigenschaften endlicher Ganzahlen
>> > ist, dass sie einen endlichen Wertebereich haben.
>>
>> Richtig. Es ist aber eine unsinnige Idee, dieser Wertebereich sei
>> grundsaetzlich identisch mit dem durch die Archtektur ermoeglichten
>> Darstellungsbereich.
>
>Es ist ein unsinniges Vorhaben, in dem Tempo, in dem sich die
>mathematische Definition des Begriffes 'Zahl' ändert (sind 'wir' immer
>noch bei 2d-Vektoren mit 'imaginärem Anteil'?), geeignete
>Repräsentationen zu ersinnen.

Du sprachst von (endlichen) Ganzzahlen. Deren Definition duerfte sich
seit ein paar hundert Jahren nicht geaendert haben und ich zweifle,
dass das in naechster Zeit passieren wird. Was soll dieser unsinnige
Einwurf?

>> > als Fehler kommt sowas normalerweise nicht vor
>>
>> Komisch. Habe ich schon oft erlebt, in allen moeglichen und unmoeglichen
>> Varianten. Es koennte uebrigens sein, dass Du es einfach nur nicht
>> merkst.
>
>Das könnte es.

Eben.

>Es könnte im übrigen auch sein, daß ich ein großer,

>rosafarbener Krake bin, [...]

Dein Problem ist offensichtlich eine etwas zu hohe
Selbsteinschaetzung. Oder Du bist tatsaechlich so perfekt.

>> > Vor allem, warum sollte man das anstelle zuverlaessiger
>> > Ganzahlarithmetik wollen, wenn man schon rechnen muss? Lisp hat
>> > welche. Ada IIRC nicht.
>>
>> Was hat Ada nicht? Ich kann Dir hier nicht ganz folgen. Modulare Typen,
>> d.h. also Typen, bei denen der Ueberlauf erlaubt und definiert ist, hat
>> Ada jedenfalls. Wenn es mit Spass macht, kann ich mir da sogar einen
>> modulo-13-Typen definieren.
>>
>> Ganzzahlarithmetik ist uebrigens per se zuverlaessig, solange sie
>> innerhalb des definierten Bereichs bleibt.
>
>Gehen sie sofort über Steele und nicht über Los.

Meinst Du http://www.lysator.liu.se/c/hs-errata.html?

Kannst Du gelegentlich auch mal meine Fragen beantworten? Wo ist
Ganzzahl-Arithmetik unzuverlaessig (von SEU-Problemen, die Dich
ueberall treffen koennen, mal abgesehen)?

>> > Nein. Es erscheint mir wuenschenswert, dass Leute, die Programme
>> > schreiben, mit solchen Begriffen vertraut sind und sie bei dieser
>> > Taetigkeit 'nutzbringend' einsetzen.
>>
>> Genau das machst Du mit SPARK.
>
>Und ohne.

Mit SPARK waere es um Groessenordnungen weniger fehleranfaellig. Und
bei gleicher Rate an Fehlern im Endprodukt waere die Entwicklungszeit
und damit die Kosten um einiges hoeher. Das ist der Punkt.

Um mal zu Deinem Beispiel vom Mechaniker zurueckzukommen: Ein guter
Mechaniker wird Dir ein beliebiges System in endlicher Zeit in
befriedigendem Masse fertigstellen koennen, auch, wenn ihm
moeglicherweise nur ein Schweizer Armeemesser zur Verfuegung steht.
Hat er dazu aber die besser geeigneten Werkzeuge, wird er das
schneller koennen. Eventuelle Unschaerfen in der Wortwahl sind hier
beabsichtigt.


Vinzent.

Vinzent Hoefler

unread,
Jan 29, 2003, 11:59:41 PM1/29/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> wrote:

>Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
>
>>Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>>> Rainer Weikusat wrote:
>>>
>>> Wo sind in C Typen zahlgenau angegeben? In C ist fuer verschiedene Typen
>>> ein Mindestbereich angegeben, den der Typ darstellen koennen muss, das
>>> war's.
>>
>>Du möchtest /usr/include/stdint.h durchlesen.
>
>Wenn es auf meinem System denn vorhanden waere.

Habe es mir gerade noch mal auf dem anderen System angesehen. Ich
finde da nichts, was darauf hindeutet, dass beispielsweise ein
unsigned int auf einem 24bittigen DSP, einem 32bittigen x86 oder einer
beliebigen 64bittigen Maschine den exakt gleichen Zahlenbereich
abdeckt und damit immer an der gleichen Stelle einen Ueberlauf
erzeugen wuerde.

Der Standard schreibt ja auch nur vor, welche Zahlenbereiche von
welchem elementaren Typen abgedeckt sein *muessen*. Aber das schrieb
ich schon.


Vinzent.

Rainer Weikusat

unread,
Jan 30, 2003, 2:37:11 AM1/30/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Vinzent Hoefler <JeLlyFish...@gmx.net> wrote:
> >Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
> >>Du möchtest /usr/include/stdint.h durchlesen.
> >
> >Wenn es auf meinem System denn vorhanden waere.
>
> Habe es mir gerade noch mal auf dem anderen System angesehen. Ich
> finde da nichts, was darauf hindeutet, dass beispielsweise ein
> unsigned int auf einem 24bittigen DSP, einem 32bittigen x86 oder einer
> beliebigen 64bittigen Maschine den exakt gleichen Zahlenbereich
> abdeckt

Das steht zu hoffen, denn es würde dem Grund für die Existenz dieser
Typen direkt zuwiderlaufen ("A «plain» int object has the natural size
suggested by the architecture of the execution environment"
[6.2.5#5]). Warum hast Du den Teil mit Typen festgelegter Größe
übersehen?

Rainer Weikusat

unread,
Jan 30, 2003, 3:53:07 AM1/30/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
> >Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> >> Rainer Weikusat wrote:
> >Du möchtest /usr/include/stdint.h durchlesen.
>
> Wenn es auf meinem System denn vorhanden waere.

Es wird irgendwo.

> limits.h sagt mir jedenfalls gerade mal, welche Zahlenbereiche in den
> momentan auf dem System verwendeten Typen darstellbar sind.
>
> >> Das sagst exakt nichts ueber die aktuelle Darstellbarkeit
> >> darueber hinaus gehender Zahlen aus.
> >
> >Ach?
>
> Auf dem zufaellig aktuellen System magst Du dazu in der Lage sein.

Der böse Prozessor ... kann der doch echt keine 36-Bit-Zahlen in
5-Bit-Registern speichern. Sowas ...

> >> Aber bilde doch in C bitte mal zahlgenau folgendes ab:
> >>
> >> type Timer is range 2 .. 65535;
> >
> >Könntest Du vielleicht einen Algorithmus Deiner Wahl, der sowas
> >braucht, in eine Maschinensprache Deiner Wahl übersetzen und Du
> >bekommst dann eine C-Variante von mir davon, sobald ich dazu komme,
> >diese Sprache zu lernen?
>
> Gee. Natuerlich wird es intern in passende Maschinenworte umgesetzt.

Also nein. Ohne eine sinnvolle Verwendung dafür kann ich Dir auch
keine sinnvolle Alternative angeben.

> Trotzdem erlaubt mir das, simple Schleifen ueber den jeweiligen
> Definitionsbereich des Typs auszufuehren, ohne dass ich mir
> zusaetzliche Konstanten, die das weiterhin beschreiben und wo es dann
> wieder in meiner Verantwortung liegt, die richtigen auszuwaehlen,
> definieren muss:

Es liegt in Deiner Verwantwortung, den Wertebereich des Typs korrekt
anzugeben, den Namen richtig zu schreiben, keine zwei ähnlichen Namen
jemals zu verwechseln etc.

> Desweiteren erlaubt mir

[ blabla entsorgt ]

> >Außerdem will ich das nicht. Ich will
> >Maschinenworte benutzen, falls die nicht zu klein sind.
>
> Bitte:
>
> |for Timer use 32;
>
> Wo liegt Dein Problem?

Welcher Teil der Ada-Spezifikation schreibt vor, daß
Ada-Implementierungen nur auf 32-Bit-Architekturen gestattet sind?

NB: Ich habe die hier rumliegen, weil sie einen gewissen
Unterhaltungswert hat. Du brauchst nicht zu suchen.

Aber für «eventuelle Zuhörer» (dieser leicht stereotypen Dauerdebatte
um Bildunglungslücken): Wenn ich mit Werten arbeite, die in
Prozessoregister passen sollen, dann haben die notwendigerweise einen
endlichen Wertebereich und weisen bei Bereichsüberläufen ein
bestimmtes Verhalten auf. Ergo muß der Code damit zurechtkommen, falls
welche zu erwarten sind. Für die meisten Fälle stellt sich die Frage
allerdings nicht oder der Überlauf ist explizit erwünscht:

u32 y;

y = (x + 1) & 0xffff;

> Aber der Compiler ist ohnehin intelligent genug, fuer solche
> Darstellungen die jeweils effizienteste Variante zu waehlen.

Lustige Sache das. Woher weiß der Compiler bei gleichen Typen denn,
wann er die «kompakt» und wann er die «schnell» repräsentieren soll,
ohne das ich ihm das sage?

> In C hingegen artet das meist in tollste #ifdef-Orgien aus,

/* types */
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;

typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;

Ich kann da kein #ifdef erkennen. Nein, ich halte C-Implementierungen
auf Systemen, die keine 8-Bit-Bytes nativ adressieren können, nicht
für besonders sinnvoll.

> eben weil der Compiler ja nicht weiss, was fuer Zahlen Du im Typen
> gerne darstellen wuerdest. Also kann man, um portabel zu bleiben
> nicht immer einfach einen int nehmen,

sondern nur, falls man vorzeichenbehaftete Zahlen mit einer Präzision
von maximal 15 Bit darstellen möchte. Man sollte im übrigen nie
«einfach einen int» benutzen, denn die Interpretation ergibt
potentiell eine negative Zahl und das möchte man nur, falls man real
mit negativen Zahlen arbeitet.

> Wie garantierst Du die jeweils effizienteste Darstellung o.g.
> Zahlenbereiches in C?

Effizient bezogen auf was?

> >> Richtig. Es ist aber eine unsinnige Idee, dieser Wertebereich sei
> >> grundsaetzlich identisch mit dem durch die Archtektur ermoeglichten
> >> Darstellungsbereich.
> >
> >Es ist ein unsinniges Vorhaben, in dem Tempo, in dem sich die
> >mathematische Definition des Begriffes 'Zahl' ändert (sind 'wir' immer
> >noch bei 2d-Vektoren mit 'imaginärem Anteil'?), geeignete
> >Repräsentationen zu ersinnen.
>
> Du sprachst von (endlichen) Ganzzahlen. Deren Definition duerfte sich
> seit ein paar hundert Jahren nicht geaendert haben

*argh* Z ist abzählbar unendlich. Würdest Du Dir bitte den Unterschied
zwischen einer ganzen Zahl im mathematischen Sinne und einer
endlichen Binärrepräsentation einer ganze Zahl in vorsichtigen
Häppchen zu Gemüte führen?

> >> Komisch. Habe ich schon oft erlebt, in allen moeglichen und unmoeglichen
> >> Varianten. Es koennte uebrigens sein, dass Du es einfach nur nicht
> >> merkst.
> >
> >Das könnte es.
>
> Eben.
>
> >Es könnte im übrigen auch sein, daß ich ein großer,
> >rosafarbener Krake bin, [...]
>
> Dein Problem ist offensichtlich eine etwas zu hohe
> Selbsteinschaetzung. Oder Du bist tatsaechlich so perfekt.

Und «Dein Problem» ist «offensichtlich» eine «strukturelle Unfähigkeit
zum rationalen Diskurs», vulgo: Du stänkerst gegen Personen, anstatt
Dich mit ihren Aussagen auseinanderzusetzen.

> >> > Vor allem, warum sollte man das anstelle zuverlaessiger
> >> > Ganzahlarithmetik wollen, wenn man schon rechnen muss? Lisp hat
> >> > welche. Ada IIRC nicht.
> >>
> >> Was hat Ada nicht?

[...]

> >Gehen sie sofort über Steele und nicht über Los.

[...]

> Kannst Du gelegentlich auch mal meine Fragen beantworten?

Du darfst mitdenken, dann findest Du die gewünschte Antwort selbstätig
im zitierten Text. Ich bin kein Vorleseshop.

> >> > Nein. Es erscheint mir wuenschenswert, dass Leute, die Programme
> >> > schreiben, mit solchen Begriffen vertraut sind und sie bei dieser
> >> > Taetigkeit 'nutzbringend' einsetzen.
> >>
> >> Genau das machst Du mit SPARK.
> >
> >Und ohne.
>
> Mit SPARK waere es um Groessenordnungen weniger fehleranfaellig. Und
> bei gleicher Rate an Fehlern im Endprodukt waere die Entwicklungszeit
> und damit die Kosten um einiges hoeher. Das ist der Punkt.

Nee, das ist eine Behauptung ohne Beweis, die so formuliert ist, daß
man sie auch nicht beweisen könnte. Für den Preis einer Lizenz dieses
Wunderöls dürfte ich knapp ein halbes Jahr arbeiten müssen, dem
dürften ca 10^4 SLOC in einer beliebigen Sprache entsprechen (in einem
benutzbaren Zustand).

> Um mal zu Deinem Beispiel vom Mechaniker zurueckzukommen: Ein guter
> Mechaniker wird Dir ein beliebiges System in endlicher Zeit in
> befriedigendem Masse fertigstellen koennen, auch, wenn ihm
> moeglicherweise nur ein Schweizer Armeemesser zur Verfuegung steht.

Blödsinn.

Rainer Weikusat

unread,
Jan 30, 2003, 3:55:52 AM1/30/03
to
Stefan Nobis <ste...@snobis.de> writes:
> Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
> > Was bedeutet Euer beider Meinung nach Laufzeit-Verhalten?
>
> Das Laufzeitverhalten ist das, was der durch ein Programm (nicht
> vollständig) beschriebene Prozess tut.

Back again at the front of the house ...

Das System verändert in Abhängigkeit der Aktionen des Programmes
seinen Zustand.

Rainer Weikusat

unread,
Jan 30, 2003, 4:45:15 AM1/30/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Kommt mir absolut nicht so vor, da Du offensichtlich formale Methoden
> ablehnst und Dir der Quelltext als Erkenntnis fuer das korrekte
> Arbeiten des Programms offensichtlich vollkommen ausreichend
> erscheint.

Mehr gibts nunmal nicht. Außer Spinnereien, versteht sich.

> >> Nein, diese Beschreibung ist mitnichten vollstaendig. Was tut das
> >> System, wenn die Software einen Zeiger dereferenziert, der auf ein
> >> zufaellig bereits freigegebenes Objekt zeigt?
> >
> > Wie passiert das ohne im Quellcode auffindbar zu sein?
>
> Wer sagt, dass das nicht auffindbar waere? Aber was am Quelltext
> beschreibt nun, was da passiert?

Welche Information fehlt Dir, um es als «Fehler» zu erkennen?

> >> Was passiert, wenn mit den Ergebnissen aus uninitialisierten
> >> Variablen gerechnet wird?
> >
> > Dann wird mit uninitialsierten Variablen gerechnet. Das konkrete Ergebnis
> > Ergebnis ist falsch und somit egal.
>
> Aber es ist im Source wohl kaum vollstaendig beschrieben.

Doch. «Rechnen mit zufälligen Werten». Genau das passiert. Das Konzept
«Zufall» müssen wir nicht separat klären, nein?

> >> Das ganze ist nicht einmal mehr deterministisch, was willst Du da
> >> mit dem Source anfangen?
> >
> > Beides korrigieren. Warum?
>
> Weil Du sagtest, der Source wuerde das Verhalten des System vollstaendig
> beschreiben.

Der Quelltext beschreibt das Verhalten des Programmes vollständig. Aus
offensichtlichen Gründen setzt jeglicher «Beweis» genau auf dieser
Annahme auf: Es passiert das, was im Code steht. Dieser Code arbeitet
auf einer bestimmten Abstraktionsebene, die irgendwelche Eigenschaften
hat, die nicht Bestandteil von ihm selber sind.

> >> Und *Du* kannst bei 100KSLOC *garantieren*, dass keiner dieser Fehler
> >> auftritt?
> >
> > Spielt das eine wesentliche Rolle, falls man das muß?
>
> Sogar eine sehr wesentliche.

Kaum. «Müssen» bedeutet, «nicht können» ist ausgeschlossen,
verallgemeinert: Du hast irgendwelche Anforderungen, denen das Ergebnis
Deiner Arbeit zu genügen hat, die nicht in Deinem Belieben stehen.

> >> > Es ist möglich, eine 100.000-Zeilen-Programm so zu konstruieren,
> >> > daß man keine Einheiten von mehr als maximal tausend Zeilen hat und
> >> > so, daß diese Einheiten keine internen Abhängigkeiten haben.
> >>
> >> Ja. Was nicht heisst, dass es nachher funktioniert.
> >
> > Falls der Entwurf Müll war, bekommt man ein korrektes Programm, das
> > Müll tut.
>
> Auch.

Immer.

> >> Und in SPARK durch den Beweis der Abwesenheit von Laufzeitfehlern
> >> garantieren kann.
> >
> > Lies das bitte mal durch
> >
> > <URL:http://www.freesoft.org/CIE/RFC/1035/43.htm>
> >
> > und erkläre mir bitte danach, wie eine Überlaufprüfung
>
> Es ging nicht um Ueberlaufpruefung, es ging um Laufzeitfehler.

Ich hatte ein Beispiel für einen Laufzeitfehler genannt.

> > mir gegen data corruption, die aufgrund einer verpeilten
> > Implementierung ohne das> höchstwertige Bit im Offset auftritt,
> > falls es für die befragte zone soviel secondaries gibt, daß in der
> > addtional info section> Rückverweise > 255 vorkommen.
>
> Sorry, aber wenn Daten A durch eine verpeilte Implementierung so zu
> Daten B mutiert werden, dass sie trotzdem noch als gueltig anerkannt
> werden, dann hast Du auf *jedem* System Pech gehabt.

Read: Schon bei trivialen semantischen Fehlern bin ich dann doch
wieder bloß auf mich gestellt.

> Was wolltest Du damit sagen? Dass, wenn ich eine Fehlerklasse nicht
> ausschliessen kann, es unsinnig ist, andere auszuschliessen?

Solange ich nicht beweisbar alle «Fehlerklassen» «ausgeschlossen»
habe, hängt die Funktionsfähigkeit des Endergebnisse genauso wie
vorher vom Entwickler ab und beurteilen kann *ich* das, in dem ich
seinen Quellcode auf eine meine Wissensbegierde befriedigende Weise
inspiziere. Und jeder andere kann das.

Sorry, Pal, aber blind vertraue ich weder Dir noch einer
«Wundermaschine».

> >> >> It is easier to fit the specification to a program than vice
> >> >> versa?
> >> >
> >> > Entweder das Programm ist eine Übersetzung der Spezifikation in
> >> > eine andere Sprache oder Du hast einen schrecklichen Fehler
> >> > gemacht, der sich auch mit 400t glue code im Nachhinein nicht mehr
> >> > wird reparieren lassen.
> >>
> >> Sorry, entweder Du traeumst oder Du bist einer von denen, die immer
> >> auf Anhieb korrekte, der Spezifikation entsprechende Software
> >> schreiben koennen. Wieviele Fehler hast Du im Durchschnitt pro
> >> Tausend Zeilen Code?
> >
> > Das ist die falsche Frage. «Wie lange dauert es, bis 1000 Zeilen Code
> > fehlerfrei sind?»
>
> Meinetwegen auch das. Wie lange dauert es also, bis Du die
> durchschnittlich 10 Fehler ausgemerzt hast?

Solange. Falls Du welche meinst, die das Programm letal an der
Funktion hindern würde ich 2½ Tage zum Schreiben veranschlagen und
einen, um das Resultat in einen Zustand zu bringen, in dem es seine
Hauptfunktionen zuverlässig erfüllt. Da könnte man jetzt noch maximal
zwei Tage dazuzählen, um abseitigere Codepfade zu korrigieren.

NB: Grundvorrausetzung ist, das die Struktur bis auf Details
bereits festliegt. Das ist der Teil, der normalerweise Zeit
braucht.

> >> Beim MultOS-CA hat man 38 Fehler aus der Spezifikationsphase erst in
> >> der Kodierphase gefunden und einen waehrend der Operation.
> >
> > Zuviele Details.
>
> Irrtum, zu wenige. Ein Teil der Spezifikation war nachweislich nicht
> eindeutig.

Wenn die Spezifikation eine bestimmte Implementierung eindeutig
beschreibt, ist sie zu detailliert.

> >> Dann solltest Du die Leute grundsaetzlich wegen Unfaehigkeit feuern.
> >
> > Ich behelfe mir lieber damit, nichts wiederzuverwenden, was trivial
> > reimplementierbar ist.
>
> Toll. Klasse. Dein Nachfolger dann auch.

Das ist zum Glück nicht mein Problem.

> > Das, wovon Du redest, würde ich «design flaws» im Interface
> > nennen.
>
> Nein.

Was denn?

> > Vermutlich. Aber das kürzlich für den häufigsten Luftfahrtunfall heißt
> > «CIFT», was für «controlled flight into terrain» steht, dh der Pilot
> > fliegt gegen den Berg und warum bleibt ein Geheimnis.
>
> Niemand sagt, dass Software fehlerfrei waere. Angenommen, es waere ein
> Softwarefehler, wuerdest Du sicher garantieren, dass die Software
> korrekt waere, wenn Du sie geschrieben haettest?

Es ist technisch unmöglich, Dritten die Korrektheit von irgendetwas zu
garantieren. Du kannst mir einen Satz von Anforderungen nennen, dann
kann ich Dir ein Programm schreiben, welches diesen Anforderungen
meiner Meinung nach entspricht. Falls Du etwas komplizierteres als
Lichtorgeln damit zu bearbeiten gedenkst, würde ich Dir außerdem
dringend raten, die Ergebnisse unabhängig von mir zu überprüfen.

> >> Brauche ich wirklich selten. Und in Embedded Systems- bzw.
> >> Safety-Critical-Umgebungen will man das auch nicht. Es wird Dir in
> >> den seltensten Faellen gelingen, nachzuweisen, dass Deine Techniken
> >> nicht zu Speicherfragmentierung und/oder Memory-Leaks fuehren.
> >
> > Bitte? «Man kann keine Algorithmen schreiben, deren Speicherverbrauch
> > über die vollständige Laufzeit O(1) ist?»,
>
> Doch genau das kann man. Eben deshalb benoetigt man keine dynamische
> Speicherverwaltung.

O(1) heißt «Es gibt einen Konstante, die größer ist, als alle real
vorkommenden Werte» und nicht «Ich verbrauche eine im Vorraus exakt
spezifizierte Speichermenge».

> >> Auch deren Stackverbrauch, bevor die Runtime-Umgebung ein
> >> Storage_Error ausloest (oder halt nicht)?
> >
> > In Abhängigkeit von den Eingabedaten. Klar. Wieso?
>
> Das zeigst Du mir fuer eine beliebige Menge an Eingangsdaten.
> Wenn Du fertig bist.

Ok. Wir definieren einen beliebige Menge: M ::= { 1, 2, 3 }
und folgenden beliebigen Algorithmus:

void dummy(unsigned *m)
{
return *m == 3 ? 3 : dummy(m + 1);
}

Das braucht drei activation records, die minimal eine
Rücksprungadresse und einen Zeiger enthalten.

> > Das ist eine Schleife mit drei Abbruchbedingungen, von denen Du eine
> > willkürlich im Schleifenkopf positioniert hast.

> > Ich halte das für eine
> > Verwirrtaktik und
>
> Oh, Du meinst, ein for (p = ...; *p; ++p) wuerde bei Dir etwas anderes
> bedeuten?

Ich meine, daß ich von

while (condition) {
statement;
statement;
statement;
}

erwarte, daß es sich 'wie üblich' verhält, dh es gibt eine
Abbruchbedingung, einen Eintrittspunkt «oben» und einen Austrittspunkt
«unten». Falls diese Bedingungen nicht gegeben sind, bringt mir die
hervorgehobene Position keinelei Vorteile und schlimmstenfalls
behindert sie das Code-Verständnis.

> > brauchst wegen der Zählerei 'grundsätzlich' eine
> > Überlaufprüfung.
> Wo? Dort ist absolut keine Pruefung notwendig.

Du iterierst über einen Zahlenbereich, ohne dazu Vergleiche mit der
relevanten Bereichsgrenze anzustellen? Interessant ...

> > Für den Wert gibt es möglicherweise eine konstante
> > Obergröße, aber keine definierte Länge (... die nicht erst durch
> > Zählen ermittelt werden müßte).
>
> Das was Du dort benutzt hast, war ein Array auf irgendwelche
> Strukturen,

Falsch.

> das habe ich auch genauso umgesetzt, ob Du dort nun Deinen Endemarker
> drin hast oder nicht ist egal, denn das Array muss irgendwo eine fest
> definierte Laenge haben.

Bloß muß die mir nicht im Vorneherein bekannt sein.

> > Das halte ich für «debatable». Weniger Komplexität ist der bessere
> > Weg.
>
> Eben. Deswegen will man Pointer vermeiden. Sie fuehren zu komplexem
> undurchschaubaren Code, der durch Abstraktion teilweise stark
> vereinfacht werden kann.

Das ist gelogen.

Rainer Weikusat

unread,
Jan 30, 2003, 4:51:36 AM1/30/03
to
Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
> irrelevant, wenn zwar A's programm korrekt ist, aber B's
> implementierung von syscall #6 nicht stimmt.
>
> Es wird viel daran gearbeitet, korrekt arbeitende
> Uebersetzer zu produzieren. SPARK geht in diese Richtung.
>
> Ich glaube nicht, dass irgendeiner der tool-verfechter fehlerhafte
> Bib-Funktionen oder kaputte Laufzeitsysteme ignorieren wuerde.

4.2 Practical Issues 2 - The "Cosmic Ray" problem

During a presentation of this approach, you can bet good money
that someone at the back of the room will pop their hand up
and say "Aha! But what about cosmic rays!" This is indeed a
good point that warrants some consideration. Our analytical
model is valid with respect to certain assumptions--namely the
canonical semantics of SPARK, the trustworthiness of a
compiler, and the reliability of the underlying hardware.

Wir irren uns alle mal.

Rainer Weikusat

unread,
Jan 30, 2003, 6:08:04 AM1/30/03
to
Lutz Donnerhacke <lu...@iks-jena.de> writes:
> * Vinzent Hoefler wrote:
> > Natuerlich *kann* man in C selbst darauf achten, dass man die Funktion
> > immer mit den richtigen Parametern aufruft und dass der Aufruf dieser
> > Funktion keine Seiteneffekte hat.
>
> Viel schlimmer ist es, jedesmal wieder das korrekte Taskingverhalten zu
> implementieren.

Warum verbringt man mehrere Stunden damit, eine Gemüsebrühe für eine
Käsesoße selbst aufzusetzten, obwohl es doch jeden Untermenge aller
Bestandteile des fertigen Essens fertig zu kaufen gibt?

void log_access(char *user, char * const argv[], size_t argc)
{
int fd, rc;
char *p;
static char nl = '\n', sp = ' ';
struct iovec *iov, *cur;

if (argc > 16) argc = 16;
iov = malloc(sizeof(struct iovec) * (argc * 2 + 1));
if (!iov) {
perror("malloc");
exit(1);
}
cur = iov;

fd = open(LOG, O_WRONLY | O_CREAT | O_APPEND, 0600);
if (fd == -1) {
perror("open");
exit(1);
}

p = strchr(user, 0);
*p = ':';
cur->iov_base = user;
cur->iov_len = p - user + 1;
++cur;

while (1) {
cur->iov_len = strlen(*argv);
cur->iov_base = *argv;
++cur;
++argv;
if (!*argv) break;
cur->iov_base = &sp;
cur->iov_len = 1;
++cur;
}
cur->iov_base = &nl;
cur->iov_len = 1;

rc = writev(fd, iov, argc * 2 + 1);
if (rc == -1) {
perror("writev");
exit(1);
}

rc = close(fd);
if (rc == -1) {
perror("close");
exit(1);
}

free(iov);
}

... und läßt sich hinterher auch noch deswegen von Leuten beschimpfen,
die sich durch diese Tatsache in ein ungünstiges Licht gerückt fühlen?

... und warum tut man das ohne jegliche soziale Absicherung zu einem
buchstäblichen Hungerlohn?

Die Antwort lautet: Weil einem etwas an der Sache liegt und nicht
daran, «Anerkennung» zu erheischen.


Stefan Nobis

unread,
Jan 30, 2003, 6:18:10 AM1/30/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> O(1) heißt «Es gibt einen Konstante, die größer ist, als alle real
> vorkommenden Werte» und nicht «Ich verbrauche eine im Vorraus exakt
> spezifizierte Speichermenge».

Mein Gott! Diesen grausigen Unsinn kann man sich ja nicht mit ansehen.

Wenn du schon mit in jedem billigen Lehrbuch über Informatik
definierten Begriffen um dich wirfst, die du offensichtlich nicht
verstanden hast, schreibe die Definitionen doch bitte ab.

f = O(g) :<=> Es existiert eine reelle Zahl c und eine natürliche Zahl
k, so dass für alle natürlichen Zahlen n >= k gilt: f(n) <= c * g(n).

So einfach. Wenn du jetzt g(n) = 1 setzt, ergibt dies: f(n) <= c. Also
ist der Speicherverbrauch ab einem gewissen n fortan konstant und
*völlig* unabhängig von den Eingabedaten!

O(1) bedeutet konstanter Aufwand/Verbrauch, unabhängig von den
Eingabedaten.

Und diese Konstante c ist eine ganz normale reelle Zahl und nicht
irgendein ominöses "größer als alle real vorkommenden Werte". Was wäre
das für eine hirnverbrannte und sinnlose Definition.

> > Eben. Deswegen will man Pointer vermeiden. Sie fuehren zu komplexem
> > undurchschaubaren Code, der durch Abstraktion teilweise stark
> > vereinfacht werden kann.

> Das ist gelogen.

Deine sachliche Argumentation und die Stringenz deiner Ausführungen
begeistern mich immer wieder.

Rainer, du trollst.

--
Stefan.

Georg Bauhaus

unread,
Jan 30, 2003, 6:57:37 AM1/30/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

:> Ich glaube nicht, dass irgendeiner der tool-verfechter fehlerhafte

:> Bib-Funktionen oder kaputte Laufzeitsysteme ignorieren wuerde.
:
: model is valid with respect to certain assumptions--namely the

: canonical semantics of SPARK, the trustworthiness of a
: compiler, and the reliability of the underlying hardware.

Ignorieren: nicht wissen wollen; absichtlich uebersehen,
nicht beachten.

von Buechereien sehe ich in dem Zitat auch nichts.

: Wir irren uns alle mal.


Lutz Donnerhacke

unread,
Jan 30, 2003, 6:59:37 AM1/30/03
to
* Rainer Weikusat wrote:
> Lutz Donnerhacke <lu...@iks-jena.de> writes:
>> * Vinzent Hoefler wrote:
>> > Natuerlich *kann* man in C selbst darauf achten, dass man die Funktion
>> > immer mit den richtigen Parametern aufruft und dass der Aufruf dieser
>> > Funktion keine Seiteneffekte hat.
>>
>> Viel schlimmer ist es, jedesmal wieder das korrekte Taskingverhalten zu
>> implementieren.
>
> Warum verbringt man mehrere Stunden damit, eine Gemüsebrühe für eine
> Käsesoße selbst aufzusetzten, obwohl es doch jeden Untermenge aller
> Bestandteile des fertigen Essens fertig zu kaufen gibt?

Das war exakt meine Frage. Warum forderst Du die beständige Reimplementation
von vorhandenen Funktionen, wenn die anbietende Sprache Dir zu komplex
erscheint?

BTW:


> rc = writev(fd, iov, argc * 2 + 1);
> if (rc == -1) {
> perror("writev");
> exit(1);
> }

Das ist schlicht falsch implementiert.

> ... und warum tut man das ohne jegliche soziale Absicherung zu einem
> buchstäblichen Hungerlohn?

Die Frage geht an Dich.

> Die Antwort lautet: Weil einem etwas an der Sache liegt und nicht
> daran, «Anerkennung» zu erheischen.

Warum reimplementierst Du syslog(3) falsch?

Georg Bauhaus

unread,
Jan 30, 2003, 7:00:33 AM1/30/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

: Entweder Du akzeptierst die Semantik der Sprache, dann ist die

: 'Bedeutung' von = klar oder Du machst das nicht. Aber bitte ueberall,
: egal wie rum.

Wenn wie in C++ moeglich, '=' umdefiniert werden kann,
zum Beispiel fuer smart pointer, ist es in einem grossen
Programm moeglich, aber nicht einfach, hier zur Klarheit
zu gelangen.

Georg Bauhaus

unread,
Jan 30, 2003, 7:11:27 AM1/30/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

: da
: alle Beteiligten ausser mir die Existenz fehlerfreier Programme
: ausschliessen,

Glaube ich nicht. Die Frage nach fehlerfreien Programmen
ist wohl mehr als eine empirische aufgefasst, als eine nach
der prinzipiellen Moeglichkeit, Programme korrekt zu schreiben
und/oder nachzuweisen.

(Im Sinn von int main(int a, char** A) { return a; },
was mit der nuetzlichen vereinfachung int f(int a) { return a;}
in ziemlich direkter Entsprechung zum Hochsprachen code in/auf
hardware realisiert werden koennte, ohne das Zweifel an der
Fehlerfreiheit Oberhand naehmen.)

Rainer Weikusat

unread,
Jan 30, 2003, 7:18:37 AM1/30/03
to
Stefan Nobis <ste...@snobis.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
>
> > O(1) heißt «Es gibt einen Konstante, die größer ist, als alle real
> > vorkommenden Werte» und nicht «Ich verbrauche eine im Vorraus exakt
> > spezifizierte Speichermenge».
>
> Mein Gott! Diesen grausigen Unsinn kann man sich ja nicht mit
> ansehen.

> Wenn du schon mit in jedem billigen Lehrbuch über Informatik
> definierten Begriffen um dich wirfst, die du offensichtlich nicht
> verstanden hast, schreibe die Definitionen doch bitte ab.
>
> f = O(g) :<=> Es existiert eine reelle Zahl c und eine natürliche Zahl
> k, so dass für alle natürlichen Zahlen n >= k gilt: f(n) <= c *
> g(n).

In Worten: "Es gibt eine *Konstante* (c), die größer ist als
alle real vorkommenden Werte."

Würdest Du bitte ein Minimum an Deutsch lernen, bevor Du Dich unter
Menschen traust?

NB: Der konkrete Aufwand ist für jeden Programmdurchlauf konstant,
allerdings *weder*

- zwangsläufig von vorneherein bekannt
- für jeden durchlauf identisch

Falls Du noch ein Codebeispiel dafür brauchst, laß es mich bitte
wissen. Kurz sieht das so aus:

a) es gibt maximal n Eingabedatenpakete, für die gleichzeitig
Platz belegt wird

b) diese n Eingabedatenpakete zerfallen in Einheiten zu m
Paketen (mit m variabel und <= n), für die ich wiederum
«bestimmte Verwaltungsdaten» benötige.

Offensichtlich ist a O(1) und b O(n), aber wegen m <= n ist die
Gesamtmenge ebenfalls nach oben durch eine Konstante limitiert,
konkret 4096a + maximal 4095b. Die konkrete Menge hängt von der
internen Strukur der Eingabedaten ab, *NICHT* ihre Obergrenze.

Rainer Weikusat

unread,
Jan 30, 2003, 7:23:06 AM1/30/03
to
Lutz Donnerhacke <lu...@iks-jena.de> writes:
> * Rainer Weikusat wrote:
> > Lutz Donnerhacke <lu...@iks-jena.de> writes:
> BTW:
> > rc = writev(fd, iov, argc * 2 + 1);
> > if (rc == -1) {
> > perror("writev");
> > exit(1);
> > }
>
> Das ist schlicht falsch implementiert.

'Falsch implementiert' würde ich als 'die reale Semantik widerspricht
der intendierten Semantik' definieren. Sie tut das nicht.

Rainer Weikusat

unread,
Jan 30, 2003, 7:24:22 AM1/30/03
to
Stefan Nobis <ste...@snobis.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
>
> > O(1) heißt «Es gibt einen Konstante, die größer ist, als alle real
> > vorkommenden Werte» und nicht «Ich verbrauche eine im Vorraus exakt
> > spezifizierte Speichermenge».
>
> Mein Gott! Diesen grausigen Unsinn kann man sich ja nicht mit
> ansehen.

> Wenn du schon mit in jedem billigen Lehrbuch über Informatik
> definierten Begriffen um dich wirfst, die du offensichtlich nicht
> verstanden hast, schreibe die Definitionen doch bitte ab.
>
> f = O(g) :<=> Es existiert eine reelle Zahl c und eine natürliche Zahl
> k, so dass für alle natürlichen Zahlen n >= k gilt: f(n) <= c *
> g(n).

In Worten: "Es gibt eine *Konstante* (c), die größer ist als
alle real vorkommenden Werte."

Würdest Du bitte ein Minimum an Deutsch lernen, bevor Du Dich unter
Menschen traust?

NB: Der konkrete Aufwand ist für jeden Programmdurchlauf konstant,
allerdings *weder*

- zwangsläufig von vorneherein bekannt
- für jeden durchlauf identisch

Falls Du noch ein Codebeispiel dafür brauchst, laß es mich bitte
wissen. Kurz sieht das so aus:

a) es gibt maximal n Eingabedatenpakete, für die gleichzeitig
Platz belegt wird

b) diese n Eingabedatenpakete zerfallen in Einheiten zu m
Paketen (mit m variabel und <= n), für die ich wiederum
«bestimmte Verwaltungsdaten» benötige.

Offensichtlich ist a O(1) und b O(n), aber wegen m <= n ist die
Gesamtmenge ebenfalls nach oben durch eine Konstante limitiert,

konkret maximal 4096a + maximal 4095b. Die konkrete Menge für den
zweiten Anteil hängt von der internen Strukur der Eingabedaten ab,
*NICHT* ihre Obergrenze.

Georg Bauhaus

unread,
Jan 30, 2003, 7:25:31 AM1/30/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
:> > Was bedeutet Euer beider Meinung nach Laufzeit-Verhalten?
:> vollst?ndig) beschriebene Prozess tut.
: Das System ver?ndert in Abh?ngigkeit der Aktionen des Programmes
: seinen Zustand.

Ich muss nochmal fragen, weil jetz auf einmal Prozess und System
auftauchen, was ist mit einem Prozessor mit einem Eingang, und einem
Ausgang, einem stack, sonst nichts, und dem programm

in
add 1
out

Angenommen add ist wohldefiniert, kann ich davon ausgehen,
dass der Laufzeitprozess vorhersagbar ist, und kann ich davon
ausgehen, dass, je nach definition von "System",
(a) das system nur den Zustand "programm zu ende" von
"prozessor-start" aus erreicht, old stack = new stack
(b) zusaetzlich die I/O-register (zB) mit ihren Zustand
aendern? (Aber andererseits keinen weiteren einfluss auf den
Ablauf des programs haben werden, weil es zu Ende ist.)
Etwas in der Art?

Rainer Weikusat

unread,
Jan 30, 2003, 7:31:29 AM1/30/03
to
Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
> :> Ich glaube nicht, dass irgendeiner der tool-verfechter fehlerhafte
> :> Bib-Funktionen oder kaputte Laufzeitsysteme ignorieren wuerde.
> :
> : model is valid with respect to certain assumptions--namely the
> : canonical semantics of SPARK, the trustworthiness of a
> : compiler, and the reliability of the underlying hardware.
>
> Ignorieren: nicht wissen wollen; absichtlich uebersehen,
> nicht beachten.

Genau das steht da oben: Falls man bestimmte Möglichkeiten außer acht
läßt, ist das Modell gültig.

> von Buechereien sehe ich in dem Zitat auch nichts.

<URL:http://www.sparkada.com/publications.html#SigAda2002>

Rainer Weikusat

unread,
Jan 30, 2003, 7:35:43 AM1/30/03
to
Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
> in
> add 1
> out
>
> Angenommen add ist wohldefiniert, kann ich davon ausgehen,
> dass der Laufzeitprozess vorhersagbar ist, und kann ich davon
> ausgehen, dass, je nach definition von "System",
> (a) das system nur den Zustand "programm zu ende" von
> "prozessor-start" aus erreicht, old stack = new stack
> (b) zusaetzlich die I/O-register (zB) mit ihren Zustand
> aendern? (Aber andererseits keinen weiteren einfluss auf den
> Ablauf des programs haben werden, weil es zu Ende ist.)
> Etwas in der Art?

Das wäre ein extrem simplifiziertes Beispiel. Ich hatte eher an eine
Menge von Programmen und Hardware gedacht, die interagieren. Den
Zustand dieses «Systems» kann ich nicht aus einem Programmquelltext
ergründen (und auch nicht aus allen, es fehlen wechselseitige
Einflüsse), aber falls ich ein paar vereinfachende Annahmen mache,
kann ich Aussagen über das Verhalten des Programmes machen, solange
diese Annahmen zutreffen. Nichts anderes tut ein Beweis.

Georg Bauhaus

unread,
Jan 30, 2003, 7:56:40 AM1/30/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

: Ok. Wir definieren einen beliebige Menge: M ::= { 1, 2, 3 }

: und folgenden beliebigen Algorithmus:
:
: void dummy(unsigned *m)
: {
: return *m == 3 ? 3 : dummy(m + 1);
: }

Ein ganz gutes Beispiel, weil es einiges zeigt.
Es ist uebersetzbar.
Eine void funktion kann 3 zurueckgeben.
Der Aufruf dummy(m + 1) fuehrt Zeiger-Arithmetik durch.
Die Anzahl der Aufrufe ist somit nicht leicht vorhersagbar.

: Das braucht drei activation records, die minimal eine
: R?cksprungadresse und einen Zeiger enthalten.

Gruesse, Georg

Rainer Weikusat

unread,
Jan 30, 2003, 8:16:21 AM1/30/03
to
Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
>
> : Ok. Wir definieren einen beliebige Menge: M ::= { 1, 2, 3 }
> : und folgenden beliebigen Algorithmus:
> :
> : void dummy(unsigned *m)
> : {
> : return *m == 3 ? 3 : dummy(m + 1);
> : }
>
> Ein ganz gutes Beispiel, weil es einiges zeigt.
> Es ist uebersetzbar.
> Eine void funktion kann 3 zurueckgeben.
> Der Aufruf dummy(m + 1) fuehrt Zeiger-Arithmetik durch.
> Die Anzahl der Aufrufe ist somit nicht leicht vorhersagbar.

Die Beschreibung ist Müll. Aber von Dingen, die ich abends ohne
Absicht, sie jemals an einen Compiler zu verfüttern, nach Konsum einer
gewissen Alkoholmenge von mir gebe, darf man das erwarten. Aber weils
so schön ist:

unsigned m[2] = { 1, 2, 3 };

void dummy(unsigned *m)
{
if (*m == 3) return;
dummy(m + 1);
}

.
.
.

dummy(m);

Lutz Donnerhacke

unread,
Jan 30, 2003, 9:25:19 AM1/30/03
to
* Rainer Weikusat wrote:
> Lutz Donnerhacke <lu...@iks-jena.de> writes:
>> * Rainer Weikusat wrote:
>> > rc = writev(fd, iov, argc * 2 + 1);
>> > if (rc == -1) {
>> > perror("writev");
>> > exit(1);
>> > }
>>
>> Das ist schlicht falsch implementiert.
>
> 'Falsch implementiert' würde ich als 'die reale Semantik widerspricht
> der intendierten Semantik' definieren. Sie tut das nicht.

Tut sie. Sie schreibt zuwenig, oder bricht grundlos ab.

Vinzent Hoefler

unread,
Jan 30, 2003, 10:33:35 AM1/30/03
to
Rainer Weikusat wrote:

>> >Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
>> >>Du möchtest /usr/include/stdint.h durchlesen.
>> >

[...]


> Das steht zu hoffen, denn es würde dem Grund für die Existenz dieser
> Typen direkt zuwiderlaufen ("A «plain» int object has the natural size
> suggested by the architecture of the execution environment"
> [6.2.5#5]).

Eben. Also nichts mit festgelegtem Zahlenbereich.

> Warum hast Du den Teil mit Typen festgelegter Größe
> übersehen?

Toll, da hast Du Typen mit festgelegter Groesse, ohne zu wissen, ob die
auf der Maschine effizient umgesetzt werden koennen.


Vinzent.

--
"He could be a poster child for retroactive birth control."

Rainer Weikusat

unread,
Jan 30, 2003, 11:11:32 AM1/30/03
to

Sie schreibt exakt dann zuwenig, falls die Platte voll ist (physisch
oder wegen quota) und bricht unter keinen Umständen grundlos
ab. Details dazu findest Du in epischer Breite in APUE, S. 275ff.

Rainer Weikusat

unread,
Jan 30, 2003, 11:14:57 AM1/30/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Rainer Weikusat wrote:
> > Warum hast Du den Teil mit Typen festgelegter Größe
> > übersehen?
>
> Toll, da hast Du Typen mit festgelegter Groesse, ohne zu wissen, ob
> die auf der Maschine effizient umgesetzt werden koennen.

Das gilt für jede Zahl, die nicht in ein Maschinenwort paßt. Dietz
Propper hat C mal sehr hübsch 'einen portablen Makroassembler'
genannt. Ich denke, das beschreibt Funktionsumfang und
-einschränkungen ziemlich zutreffend.

Vinzent Hoefler

unread,
Jan 30, 2003, 11:53:55 AM1/30/03
to
Rainer Weikusat wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
>> >Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> >> Rainer Weikusat wrote:
>> >Du möchtest /usr/include/stdint.h durchlesen.
>>
>> Wenn es auf meinem System denn vorhanden waere.
>
> Es wird irgendwo.

Nein. Die hier laufende DJGPP-Version kennt es nicht.

>> limits.h sagt mir jedenfalls gerade mal, welche Zahlenbereiche in den
>> momentan auf dem System verwendeten Typen darstellbar sind.
>>
>> >> Das sagst exakt nichts ueber die aktuelle Darstellbarkeit
>> >> darueber hinaus gehender Zahlen aus.
>> >
>> >Ach?
>>
>> Auf dem zufaellig aktuellen System magst Du dazu in der Lage sein.
>
> Der böse Prozessor ... kann der doch echt keine 36-Bit-Zahlen in
> 5-Bit-Registern speichern. Sowas ...

Darum geht es nicht. Es geht darum, dass ein Typ, der einen Bereich von
0 .. 10'000'000 abdecken soll, auf einem System mit 32 Bit, auf einem
anderen mit 24 Bit dargestellt werden koennte (in C mit den
Standardtypen eher nicht). Wenn man bloed genug bist, das nicht
grundsaetzlich zu beachten, kann das das Verhalten Deines Programms.

>> >> Aber bilde doch in C bitte mal zahlgenau folgendes ab:
>> >>
>> >> type Timer is range 2 .. 65535;
>> >
>> >Könntest Du vielleicht einen Algorithmus Deiner Wahl, der sowas
>> >braucht, in eine Maschinensprache Deiner Wahl übersetzen und Du
>> >bekommst dann eine C-Variante von mir davon, sobald ich dazu komme,
>> >diese Sprache zu lernen?
>>
>> Gee. Natuerlich wird es intern in passende Maschinenworte umgesetzt.
>
> Also nein. Ohne eine sinnvolle Verwendung dafür kann ich Dir auch
> keine sinnvolle Alternative angeben.

|function Clamp_Timer (Value : in float) return Timer is
|begin
| if (Value < Timer'First)
| return Timer'First;
| elsif (Value > Timer'Last)
| return Timer'Last;
| else
| return Timer (Float'Floor (Value));
| end if;
|end Clamp_Timer;

Warum sollte es hier in meiner unmittelbaren Verantwortung liegen die
wirklich passenden Konstanten herauszusuchen, wenn das der Compiler von
ganz alleine kann?

>> Trotzdem erlaubt mir das, simple Schleifen ueber den jeweiligen
>> Definitionsbereich des Typs auszufuehren, ohne dass ich mir
>> zusaetzliche Konstanten, die das weiterhin beschreiben und wo es dann
>> wieder in meiner Verantwortung liegt, die richtigen auszuwaehlen,
>> definieren muss:
>
> Es liegt in Deiner Verwantwortung, den Wertebereich des Typs korrekt
> anzugeben, den Namen richtig zu schreiben, keine zwei ähnlichen Namen
> jemals zu verwechseln etc.

Richtig. Und deswegen erlaube ich es mir, es fuer besser zu halten, wenn
mir der Compiler dabei hilft, dieser Verantwortung besser gerecht
werden zu koennen. Gelegentlich sollen schon Tippfehler passiert sein,
die compilierbar waren.

>> Desweiteren erlaubt mir
>
> [ blabla entsorgt ]
>
>> >Außerdem will ich das nicht. Ich will
>> >Maschinenworte benutzen, falls die nicht zu klein sind.
>>
>> Bitte:
>>
>> |for Timer use 32;
>>
>> Wo liegt Dein Problem?
>
> Welcher Teil der Ada-Spezifikation schreibt vor, daß
> Ada-Implementierungen nur auf 32-Bit-Architekturen gestattet sind?

Keiner. BTW, oben fehlt das 'Size Attribut.

Wie waere es mit:

|for Timer'Size use Integer'Size;

Wenn wir nicht gerade von 8-Bit-Maschinen reden, sollte Integer die
gerade passende Maschinenwort-Groesse haben.

> NB: Ich habe die hier rumliegen, weil sie einen gewissen
> Unterhaltungswert hat. Du brauchst nicht zu suchen.

AARM, LRM, Rationale, Quality&Style-Guide. Kein Problem, danke.

> Aber für «eventuelle Zuhörer» (dieser leicht stereotypen Dauerdebatte
> um Bildunglungslücken): Wenn ich mit Werten arbeite, die in
> Prozessoregister passen sollen, dann haben die notwendigerweise einen
> endlichen Wertebereich und weisen bei Bereichsüberläufen ein
> bestimmtes Verhalten auf.

Richtig. Nur, dass Du nicht immer weisst, welchen Bereich sie haben und
damit die Ueberlaeufe systemabhaengig sein koennen. Desweiteren moechte
ich keine Ueberlaeufe.

> Ergo muß der Code damit zurechtkommen, falls
> welche zu erwarten sind. Für die meisten Fälle stellt sich die Frage
> allerdings nicht oder der Überlauf ist explizit erwünscht:

In den meisten Faellen, in denen eine Ueberlauf stattfindet, ist das
eine Arrayindizierung und dort ist es explizit nicht erwuenscht.

> u32 y;
>
> y = (x + 1) & 0xffff;

type u32 is mod 65536;

Ist dasselbe und ich druecke damit aus, dass die Modulo-Arithmetik dort
explizit erwuenscht ist. Damit muss mein Nachfolger im Falle des Falles
nicht mehr darueber nachdenken, ob das nun ein Ueberlauf ist oder ein
implizit gewuenschtes Verhalten sein soll.

>> Aber der Compiler ist ohnehin intelligent genug, fuer solche
>> Darstellungen die jeweils effizienteste Variante zu waehlen.
>
> Lustige Sache das. Woher weiß der Compiler bei gleichen Typen denn,
> wann er die «kompakt» und wann er die «schnell» repräsentieren soll,
> ohne das ich ihm das sage?

Effizient hiess bei mir hier in erster Linie schnell, das macht der
Compiler per Default, weil das am wenigsten Arbeit verursacht.

Wenn Du es kompakt willst und Dir somit eine geschwindigkeitsmaessige
Effizienz zweitrangig ist, solltest Du es dem Compiler explizit sagen.
Dafuer gibt es ja unter anderem die representation clauses.

>> In C hingegen artet das meist in tollste #ifdef-Orgien aus,
>
> /* types */
> typedef uint8_t u8;
> typedef uint16_t u16;
> typedef uint32_t u32;
> typedef uint64_t u64;
>
> typedef int8_t i8;
> typedef int16_t i16;
> typedef int32_t i32;
> typedef int64_t i64;

Und welcher davon repraesentiert jetzt auf meinem 24-Bit-DSP das
Maschinenwort? Und auf meinem x86?

> Ich kann da kein #ifdef erkennen. Nein, ich halte C-Implementierungen
> auf Systemen, die keine 8-Bit-Bytes nativ adressieren können, nicht
> für besonders sinnvoll.

Tja. Solche Systeme gibt es aber.

>> eben weil der Compiler ja nicht weiss, was fuer Zahlen Du im Typen
>> gerne darstellen wuerdest. Also kann man, um portabel zu bleiben
>> nicht immer einfach einen int nehmen,
>
> sondern nur, falls man vorzeichenbehaftete Zahlen mit einer Präzision
> von maximal 15 Bit darstellen möchte.

Exakt.

> Man sollte im übrigen nie
> «einfach einen int» benutzen, denn die Interpretation ergibt
> potentiell eine negative Zahl

Wozu, Ueberlaeufe passieren bei Dir doch nicht?

Ich sehe hier einen kleinen Widerspruch. Einerseits sagst Du, Tests auf
Ueberlaeufe sind sinnlos, weil entweder gewuenscht oder aehnliches,
andererseits propagierst Du die Benutzung von unsigned, wenn signed
doch reichen wuerden, weil ja *potentiell* die falsche Darstellung
passieren *koennte*. Was denn nun?

> und das möchte man nur, falls man real
> mit negativen Zahlen arbeitet.

Wenn ich keine Bereichsueberlaeufe habe, ist mir das egal. Ich habe kein
Problem damit

|for i in Integer range 1 .. 15000;

zu schreiben. Wenn Du gern magst, kannst Du natuerlich auch den
passenderen Typen waehlen:

|for i in Positive range 1 .. 15000;

Ist beides aequivalent und die genaue Implementierung interessiert mich
nicht, wenn der Compiler es nicht darstellen kann, wird er es nicht
uebersetzen.

>> Wie garantierst Du die jeweils effizienteste Darstellung o.g.
>> Zahlenbereiches in C?
>
> Effizient bezogen auf was?

Auf Maschinenworte. Das war Dein Wunsch.

>> >> Richtig. Es ist aber eine unsinnige Idee, dieser Wertebereich sei
>> >> grundsaetzlich identisch mit dem durch die Archtektur
>> >> ermoeglichten Darstellungsbereich.
>> >
>> >Es ist ein unsinniges Vorhaben, in dem Tempo, in dem sich die
>> >mathematische Definition des Begriffes 'Zahl' ändert (sind 'wir'
>> >immer noch bei 2d-Vektoren mit 'imaginärem Anteil'?), geeignete
>> >Repräsentationen zu ersinnen.
>>
>> Du sprachst von (endlichen) Ganzzahlen. Deren Definition duerfte sich
>> seit ein paar hundert Jahren nicht geaendert haben
>
> *argh* Z ist abzählbar unendlich. Würdest Du Dir bitte den Unterschied
> zwischen einer ganzen Zahl im mathematischen Sinne und einer
> endlichen Binärrepräsentation einer ganze Zahl in vorsichtigen
> Häppchen zu Gemüte führen?

Ich kenne den Unterschied. Was mich allerdings weder zu sich dauernd
aendernden mathematischen Definitionen des Begriffes "Zahl" noch zu
2D-Vektoren mit imaginaeren Anteilen fuehrt, wie Dich. Dieser Einwurf
war schlichter Nonsens.

> Und «Dein Problem» ist «offensichtlich» eine «strukturelle Unfähigkeit
> zum rationalen Diskurs», vulgo: Du stänkerst gegen Personen, anstatt
> Dich mit ihren Aussagen auseinanderzusetzen.

Nein. Ich bezweifle schlicht und einfach, dass Du immer korrekten Code
schreibst.

>> >> > Vor allem, warum sollte man das anstelle zuverlaessiger
>> >> > Ganzahlarithmetik wollen, wenn man schon rechnen muss? Lisp hat
>> >> > welche. Ada IIRC nicht.
>> >>
>> >> Was hat Ada nicht?
>
> [...]
>
>> >Gehen sie sofort über Steele und nicht über Los.
>
> [...]
>
>> Kannst Du gelegentlich auch mal meine Fragen beantworten?
>
> Du darfst mitdenken, dann findest Du die gewünschte Antwort selbstätig
> im zitierten Text.

Ich schliesse daraus, dass Du behauptest: Ada haette keine zuverlaessige
Ganzzahlarithmetik. Das moechte ich erklaert wissen, weil ich dem so
widersprechen wuerde.

>> Mit SPARK waere es um Groessenordnungen weniger fehleranfaellig. Und
>> bei gleicher Rate an Fehlern im Endprodukt waere die Entwicklungszeit
>> und damit die Kosten um einiges hoeher. Das ist der Punkt.
>
> Nee, das ist eine Behauptung ohne Beweis, die so formuliert ist, daß
> man sie auch nicht beweisen könnte.

Lockheed-Martin hat ausreichend Erfahrung in Design und Implementierung
von FCS, um eine Aussage darueber machen zu koennen, dass der Einsatz
von SPARK in der C130-J eine immense Kostenerparnis durch verkuerzte
Entwicklungs-, Test- und Zertifizierungszeit gebracht hat. BTW, die
C130-J war eine Risiko-Entwicklung auf eigene Rechnung, kein
Regierungsauftrag, bevor Du dahingehend Argumente suchst.

> Für den Preis einer Lizenz dieses
> Wunderöls dürfte ich knapp ein halbes Jahr arbeiten müssen,

Keine Ahnung, was es fuer die Industrie kostet, Du bezahlst ohnehin eher
den Support, denn das Tool. Im neuen Buch von John Barnes sollten
jeweils eine Version fuer Linux und Windows drauf sein. Support ist da
sicher nicht eingeschlossen. Kostenpunkt um die 60 USD. Ich weiss
Deinen Stundensatz nicht, aber ich schaetze, das koenntest Du an einem
Tag schaffen.

> dem
> dürften ca 10^4 SLOC in einer beliebigen Sprache entsprechen

Rechnen wir mal. Die Erfahrung aus dem safety-critical-Bereich sagt,
dass ein Ingenieur am Tag ca 2-20 SLOC schreibt, relativ unabhaengig
von der Sprache. Seien wir mal optimistisch, und sagen 20. 6 Monate a
ca. 20 Arbeitstage sind 120 Arbeitstage, ergibt optimistisch
aufgerundet 2500 SLOC.

D.h. entweder bist Du tatsaechlich absolut genial, arbeitest nicht in
irgendwelchen kritischen Bereichen oder Du ueberschaetzt Dich
gnadenlos.

> (in einem benutzbaren Zustand).

Das gesamte System sind 5 MSLOC. Nein, nicht alles SPARK. Nach Deinen
Angaben braeuchtest Du dafuer 300 Monate (falls ich keinen Ueberlauf in
er Rechnung hatte... ;-) ). Und Du wuerdest nach diesen 25 Jahren das
korrekte Verhalten des Systems garantieren koennen?

>> Um mal zu Deinem Beispiel vom Mechaniker zurueckzukommen: Ein guter
>> Mechaniker wird Dir ein beliebiges System in endlicher Zeit in
>> befriedigendem Masse fertigstellen koennen, auch, wenn ihm
>> moeglicherweise nur ein Schweizer Armeemesser zur Verfuegung steht.
>
> Blödsinn.

Darf ich das so interpretieren, dass es Bloedsinn waere, dass man ein
solches System wie oben genannt mit C fertig bekommen koennte? :->


Vinzent.

--
"Don't let your mouth write no check that your tail can't cash."
-- Bo Diddley

Vinzent Hoefler

unread,
Jan 30, 2003, 12:02:54 PM1/30/03
to
Rainer Weikusat wrote:

> Georg Bauhaus <sb4...@l1-hrz.uni-duisburg.de> writes:
>> Rainer Weikusat <weik...@students.uni-mainz.de> wrote:
>> :> Ich glaube nicht, dass irgendeiner der tool-verfechter fehlerhafte
>> :> Bib-Funktionen oder kaputte Laufzeitsysteme ignorieren wuerde.
>> :
>> : model is valid with respect to certain assumptions--namely
>> : the canonical semantics of SPARK, the trustworthiness of a
>> : compiler, and the reliability of the underlying hardware.
>>
>> Ignorieren: nicht wissen wollen; absichtlich uebersehen,
>> nicht beachten.
>
> Genau das steht da oben: Falls man bestimmte Möglichkeiten außer acht
> läßt, ist das Modell gültig.

Deswegen verifiziert man den Objekt-Code, compiliert trotz "proof of
absence of runtime errors" *mit* Runtimechecks und baut Compiler, die
*jeden* Speicherzugriff zweimal checken.

Dazu baut man redundante Systeme in Hardware, selbstredend keine
identische Kopien der Software. Deswegen baut man Sensoren mit
2-out-of-3-Logik, etc. pp.

Alles das, um die Moeglichkeit einer Fehlfunktion zu *reduzieren*,
nicht, um sie mit Sicherheit *ausschliessen* zu koennen.

Wenn ich obiges zugrundelege, ist bereits im Ausdruck

|int a = 2;

nicht mehr gesichert, dass a danach nicht vielleicht doch 3 sein
koennte. Hoer einfach auf zu programmieren, wenn Du Dich darauf
verlaesst, dass dieses Modell in C oder einer beliebigen anderen
Sprache gelten wuerde.

Was ist Dein Argument? Weil es gewisse Fehlerquellen gibt, die man nicht
ausschliessen kann, kann man alle anderen Fehlerquellen auch drin
lassen, es bringt ja ohnehin nichts?


Vinzent.

--
What can you use used tampons for? Tea bags for vampires.

Rainer Weikusat

unread,
Jan 30, 2003, 12:08:56 PM1/30/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

Der 'grausige Fehler' ist übrigens das hier:

> if (argc > 16) argc = 16;

[...]

> while (1) {

[...]

> if (!*argv) break;

aber die 'Überlaufprüfung' war auch getürkt. Von ARG_MAX << UINT_MAX
darf man mE ausgehen.

Rainer Weikusat

unread,
Jan 30, 2003, 12:26:47 PM1/30/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Rainer Weikusat wrote:
> > Genau das steht da oben: Falls man bestimmte Möglichkeiten außer acht
> > läßt, ist das Modell gültig.
>
> Deswegen verifiziert man den Objekt-Code, compiliert trotz "proof of
> absence of runtime errors" *mit* Runtimechecks und baut Compiler, die
> *jeden* Speicherzugriff zweimal checken.

... und das Programm tut immer noch nicht, was es soll, weil der
Programmierer die Spezifikation aus Zeitdruck partiell ignoriert hat.

> Dazu baut man redundante Systeme in Hardware, selbstredend keine
> identische Kopien der Software.

Falls man gelten läßt, daß 'mehr Code' 'mehr unentdeckte Fehler'
bedeutet, hat man die Zuverlässigkeit des Gesamtsystems dadurch
erfolgreich vermindert. Elektronik kann ausfallen. Software nicht.

> Wenn ich obiges zugrundelege, ist bereits im Ausdruck
>
> |int a = 2;
>
> nicht mehr gesichert, dass a danach nicht vielleicht doch 3 sein
> koennte.

Weil dann auch nicht gesichert ist, daß

for (i = 0; i < 10; ++i)

nicht bereits zu

for (j = -1; j > -2; j *= 15)

mutiert ist oder zu jedem beliebigen Zeitpunkt dazu mutieren könnte,
dürfen wir jeglichen Versuch, Aussagen über Verhalten von Maschinen
zu machen, als weltfremdes Hirngespinst ad acta legen.

> Was ist Dein Argument? Weil es gewisse Fehlerquellen gibt, die man
> nicht ausschliessen kann, kann man alle anderen Fehlerquellen auch
> drin lassen, es bringt ja ohnehin nichts?

Ja. Es bringt Dir als Implementierer etwas, falls es Dir Arbeit
abnimmt. Sonst niemandem.


Vinzent Hoefler

unread,
Jan 30, 2003, 12:36:44 PM1/30/03
to
Rainer Weikusat wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Kommt mir absolut nicht so vor, da Du offensichtlich formale Methoden
>> ablehnst und Dir der Quelltext als Erkenntnis fuer das korrekte
>> Arbeiten des Programms offensichtlich vollkommen ausreichend
>> erscheint.
>
> Mehr gibts nunmal nicht.

Doch. Eine Dokumentation.

> Außer Spinnereien, versteht sich.

Klar. Kommentare sind auch unnoetig, steht ja alles im Quelltext?

>> >> Nein, diese Beschreibung ist mitnichten vollstaendig. Was tut das
>> >> System, wenn die Software einen Zeiger dereferenziert, der auf ein
>> >> zufaellig bereits freigegebenes Objekt zeigt?
>> >
>> > Wie passiert das ohne im Quellcode auffindbar zu sein?
>>
>> Wer sagt, dass das nicht auffindbar waere? Aber was am Quelltext
>> beschreibt nun, was da passiert?
>
> Welche Information fehlt Dir, um es als «Fehler» zu erkennen?

Die Information, wo genau im Quelltext der Fehler steht.
Nichtsdestotrotz beschreibt der Quelltext dann immer noch nicht das
Verhalten der Software.

>> >> Was passiert, wenn mit den Ergebnissen aus uninitialisierten
>> >> Variablen gerechnet wird?
>> >
>> > Dann wird mit uninitialsierten Variablen gerechnet. Das konkrete
>> > Ergebnis Ergebnis ist falsch und somit egal.
>>
>> Aber es ist im Source wohl kaum vollstaendig beschrieben.
>
> Doch. «Rechnen mit zufälligen Werten». Genau das passiert. Das Konzept
> «Zufall» müssen wir nicht separat klären, nein?

Und Du kannst aus dem Quellcode ablesen, wie dieser Zufallsgenerator
funktioniert?

Sorry, aber unter einer vollstaendigen Beschreibung des Systemverhaltens
stelle ich mir was anderes vor als "Keine Ahnung, was da passiert,
wahrscheinlich wird...".

>> >> Das ganze ist nicht einmal mehr deterministisch, was willst Du da
>> >> mit dem Source anfangen?
>> >
>> > Beides korrigieren. Warum?
>>
>> Weil Du sagtest, der Source wuerde das Verhalten des System
>> vollstaendig beschreiben.
>
> Der Quelltext beschreibt das Verhalten des Programmes vollständig.

Nein.

> Aus
> offensichtlichen Gründen setzt jeglicher «Beweis» genau auf dieser
> Annahme auf: Es passiert das, was im Code steht.

Ja. Solange dieser Code kein undefined behaviour beinhaltet.

>> >> > Es ist möglich, eine 100.000-Zeilen-Programm so zu konstruieren,
>> >> > daß man keine Einheiten von mehr als maximal tausend Zeilen hat
>> >> > und so, daß diese Einheiten keine internen Abhängigkeiten haben.
>> >>
>> >> Ja. Was nicht heisst, dass es nachher funktioniert.
>> >
>> > Falls der Entwurf Müll war, bekommt man ein korrektes Programm, das
>> > Müll tut.
>>
>> Auch.
>
> Immer.

Ich habe nichts gegenteiliges behauptet. Meine Aussage zielte darauf ab,
dass _*auch*_ ein korrekter Entwurf ein Ergebnis der Menge Muell
verursachen kann.

>> >> Und in SPARK durch den Beweis der Abwesenheit von Laufzeitfehlern
>> >> garantieren kann.
>> >
>> > Lies das bitte mal durch
>> >
>> > <URL:http://www.freesoft.org/CIE/RFC/1035/43.htm>
>> >
>> > und erkläre mir bitte danach, wie eine Überlaufprüfung
>>
>> Es ging nicht um Ueberlaufpruefung, es ging um Laufzeitfehler.
>
> Ich hatte ein Beispiel für einen Laufzeitfehler genannt.

Wo?

>> > mir gegen data corruption, die aufgrund einer verpeilten
>> > Implementierung ohne das> höchstwertige Bit im Offset auftritt,
>> > falls es für die befragte zone soviel secondaries gibt, daß in der
>> > addtional info section> Rückverweise > 255 vorkommen.
>>
>> Sorry, aber wenn Daten A durch eine verpeilte Implementierung so zu
>> Daten B mutiert werden, dass sie trotzdem noch als gueltig anerkannt
>> werden, dann hast Du auf *jedem* System Pech gehabt.
>
> Read: Schon bei trivialen semantischen Fehlern bin ich dann doch
> wieder bloß auf mich gestellt.

Nein. Wo liegt Dein Problem?

Wenn in einem 8-Bit-Register die Kombinationen 3, 4 und 8 erlaubt und
die anderen undefiniert sind, kannst Du fehlerhafte Konfigurationen
erkennen ('Valid). Wenn alle moeglichen 256 Zustaende auftreten
koennen, kannst Du schlicht und einfach nicht sagen, dass einer davon
falsch waere.

> Solange ich nicht beweisbar alle «Fehlerklassen» «ausgeschlossen»
> habe, hängt die Funktionsfähigkeit des Endergebnisse genauso wie
> vorher vom Entwickler ab

Natuerlich tut es das.

Du warst es ja immer, der versuchte, etwas anderes zu behaupten, indem
Du den Eindruck erwecken wolltest, der formale Beweis eines Programms
wuerde die Verantwortung, dass der Programmierer korrekten Code
schreibt auf ein anderes externes Programm verschieben.

> und beurteilen kann *ich* das, in dem ich
> seinen Quellcode auf eine meine Wissensbegierde befriedigende Weise
> inspiziere. Und jeder andere kann das.

So wie das z.B. der SPARK-Examiner tut.

> Sorry, Pal, aber blind vertraue ich weder Dir noch einer
> «Wundermaschine».

Ich auch nicht. Aber ich nehme ihre Hilfe gern an, weil ich damit
produktiver arbeiten kann, eben weil ich weiss, dass gewisse
Fehlerklassen ausgeschlossen sind und ich eben nicht grundsaetzlich
darauf selbst achten muss.

> Solange. Falls Du welche meinst, die das Programm letal an der

> Funktion hindern würde ich 2? Tage zum Schreiben veranschlagen und


> einen, um das Resultat in einen Zustand zu bringen, in dem es seine
> Hauptfunktionen zuverlässig erfüllt.

Es ging hier um korrekte Programme. Ein Programm, was nicht alle
Funktionen richtig erfuellt, ist nicht korrekt.

Was habe ich gestern erst gelesen: "It is considerably harder to write
correct programs than programs that are 'supposed to work'".

> Da könnte man jetzt noch maximal
> zwei Tage dazuzählen, um abseitigere Codepfade zu korrigieren.

Zu "korrigieren"? Welche Art von Fehlern korrigierst Du da?

> NB: Grundvorrausetzung ist, das die Struktur bis auf Details
> bereits festliegt. Das ist der Teil, der normalerweise Zeit
> braucht.

Richtig.

>> >> Beim MultOS-CA hat man 38 Fehler aus der Spezifikationsphase erst
>> >> in der Kodierphase gefunden und einen waehrend der Operation.
>> >
>> > Zuviele Details.
>>
>> Irrtum, zu wenige. Ein Teil der Spezifikation war nachweislich nicht
>> eindeutig.
>
> Wenn die Spezifikation eine bestimmte Implementierung eindeutig
> beschreibt, ist sie zu detailliert.

Das tat sie nicht. Die Spezifikation war inkonsistent, es gab also
entweder mehrere widerspruechliche Loesungen oder keine.

>> >> Dann solltest Du die Leute grundsaetzlich wegen Unfaehigkeit
>> >> feuern.
>> >
>> > Ich behelfe mir lieber damit, nichts wiederzuverwenden, was trivial
>> > reimplementierbar ist.
>>
>> Toll. Klasse. Dein Nachfolger dann auch.
>
> Das ist zum Glück nicht mein Problem.

Fuer diesen Satz wuerdest Du bei mir rausfliegen. Fristlos und ohne
Abfindung.

Das ist genau *das* Problem im Lebenszyklus einer Software, die laenger
als 3 Tage eingesetzt werden soll.

>> > Vermutlich. Aber das kürzlich für den häufigsten Luftfahrtunfall
>> > heißt «CIFT», was für «controlled flight into terrain» steht, dh
>> > der Pilot fliegt gegen den Berg und warum bleibt ein Geheimnis.
>>
>> Niemand sagt, dass Software fehlerfrei waere. Angenommen, es waere
>> ein Softwarefehler, wuerdest Du sicher garantieren, dass die Software
>> korrekt waere, wenn Du sie geschrieben haettest?
>
> Es ist technisch unmöglich, Dritten die Korrektheit von irgendetwas zu
> garantieren.

Alle moeglichen Umstaende eingerechnet, ja.

> Du kannst mir einen Satz von Anforderungen nennen, dann
> kann ich Dir ein Programm schreiben, welches diesen Anforderungen
> meiner Meinung nach entspricht.

*Deiner* Meinung nach.

> Falls Du etwas komplizierteres als
> Lichtorgeln damit zu bearbeiten gedenkst, würde ich Dir außerdem
> dringend raten, die Ergebnisse unabhängig von mir zu überprüfen.

Genau dazu gibt es den Prozess der Zertifizierung.

>> >> Brauche ich wirklich selten. Und in Embedded Systems- bzw.
>> >> Safety-Critical-Umgebungen will man das auch nicht. Es wird Dir in
>> >> den seltensten Faellen gelingen, nachzuweisen, dass Deine
>> >> Techniken nicht zu Speicherfragmentierung und/oder Memory-Leaks
>> >> fuehren.
>> >
>> > Bitte? «Man kann keine Algorithmen schreiben, deren
>> > Speicherverbrauch über die vollständige Laufzeit O(1) ist?»,
>>
>> Doch genau das kann man. Eben deshalb benoetigt man keine dynamische
>> Speicherverwaltung.
>
> O(1) heißt «Es gibt einen Konstante, die größer ist, als alle real
> vorkommenden Werte» und nicht «Ich verbrauche eine im Vorraus exakt
> spezifizierte Speichermenge».

O(1) heisst, ich brauche eine konstante (und berechenbare)
Speichermenge. Entweder mein System ist in der Lage, den benoetigten
Speicher zu liefern oder es ist es nicht. Wenn letzteres, solltest Du
nach einer anderen Loesung mit der Komplexitaet O(1) und einem
kleineren c suchen.

> Ok. Wir definieren einen beliebige Menge: M ::= { 1, 2, 3 }
> und folgenden beliebigen Algorithmus:
>
> void dummy(unsigned *m)
> {
> return *m == 3 ? 3 : dummy(m + 1);
> }
>
> Das braucht drei activation records, die minimal eine
> Rücksprungadresse und einen Zeiger enthalten.

Du hast 64 Byte Stack. Reicht das oder nicht?

>> > brauchst wegen der Zählerei 'grundsätzlich' eine
>> > Überlaufprüfung.
>> Wo? Dort ist absolut keine Pruefung notwendig.
>
> Du iterierst über einen Zahlenbereich, ohne dazu Vergleiche mit der
> relevanten Bereichsgrenze anzustellen?

Ueberlaufpruefung und Bereichsvergleiche sind durchaus etwas anderes.

Im Unterschied zu Deinem Code kann ich Dir aber sagen, dass die Schleife
irgendwann verlassen wird. Was macht Deine Schleife, wenn sie keinen
Endemarker findet? Wie garantierst Du, dass einer existiert?

> Interessant ...

loop-unrolling? ;-)

>> > Für den Wert gibt es möglicherweise eine konstante
>> > Obergröße, aber keine definierte Länge (... die nicht erst durch
>> > Zählen ermittelt werden müßte).
>>
>> Das was Du dort benutzt hast, war ein Array auf irgendwelche
>> Strukturen,
>
> Falsch.

"p++" impliziert hier pointer-Arithmetik auf einer Array-Struktur.

>> das habe ich auch genauso umgesetzt, ob Du dort nun Deinen Endemarker
>> drin hast oder nicht ist egal, denn das Array muss irgendwo eine fest
>> definierte Laenge haben.
>
> Bloß muß die mir nicht im Vorneherein bekannt sein.

Muss sie auch nicht. Der Laengenparameter kann zur Laufzeit ermittelt
sein (nicht in SPARK natuerlich). Sollte das aber auch nicht der Fall
sein, kann man die For-Schleife immer noch in eine while-Schleife
umwandeln.

>> > Das halte ich für «debatable». Weniger Komplexität ist der bessere
>> > Weg.
>>
>> Eben. Deswegen will man Pointer vermeiden. Sie fuehren zu komplexem
>> undurchschaubaren Code, der durch Abstraktion teilweise stark
>> vereinfacht werden kann.
>
> Das ist gelogen.

Wenn Du meinst.

Ich brauche so selten Pointer, weil ich mit "in/out" schaetzungsweise
ca. 90% dessen abgedeckt habe, wozu man in C Zeiger braucht. Der Rest
geht in C fuer Arrays drauf. ;->

Allein das gibt mir die Sicherheit, dass diese nie mit einem NULL-Zeiger
aufgerufen werden kann. Das verringert meines Erachtens die
Komplexitaet um betraechtliches.


Vinzent.

Vinzent Hoefler

unread,
Jan 30, 2003, 1:02:14 PM1/30/03
to
Rainer Weikusat wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:

>> [stdint.h]


>> Toll, da hast Du Typen mit festgelegter Groesse, ohne zu wissen, ob
>> die auf der Maschine effizient umgesetzt werden koennen.
>
> Das gilt für jede Zahl, die nicht in ein Maschinenwort paßt.

Richtig. Darum ging es mir aber.

> Dietz
> Propper hat C mal sehr hübsch 'einen portablen Makroassembler'
> genannt. Ich denke, das beschreibt Funktionsumfang und
> -einschränkungen ziemlich zutreffend.

Wobei ich das mit der Portabilitaet... *ok*. In Assembler weiss ich
wenigstens mit Sicherheit, wie gross die Maschinenworte sind.

Und - ehrlich gesagt -, wenn ich meine 8MHz-Maschine schon aus
Effizienzgruenden in 100% Assembler programmieren muss, benutze ich
doch fuer die anderen abstrakteren Tasks lieber eine Programmiersprache
statt eines anderen (wenn auch moeglicherweise portablen) Assembler,
mit dem man noch mehr Fehler machen kann. :->


Vinzent.

--
Politicians do it to everyone.

Rainer Weikusat

unread,
Jan 30, 2003, 1:16:46 PM1/30/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Rainer Weikusat wrote:
> > Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> >> Kommt mir absolut nicht so vor, da Du offensichtlich formale Methoden
> >> ablehnst und Dir der Quelltext als Erkenntnis fuer das korrekte
> >> Arbeiten des Programms offensichtlich vollkommen ausreichend
> >> erscheint.
> >
> > Mehr gibts nunmal nicht.
>
> Doch. Eine Dokumentation.

Mit Glück. Und vielleicht sogar eine zutreffende.

> > Außer Spinnereien, versteht sich.
>
> Klar. Kommentare sind auch unnoetig, steht ja alles im Quelltext?

Kommentare stehen auch im Quelltext. Aber grundsätzlich ist das
richtig: Die meisten Kommentare [die ich kenne] sind überflüssig,
denn Leute haben einen notorischen Hang dazu, den Code zu
'kommentieren' anstatt ihn zu erläutern.

> >> > Wie passiert das ohne im Quellcode auffindbar zu sein?
> >>
> >> Wer sagt, dass das nicht auffindbar waere? Aber was am Quelltext
> >> beschreibt nun, was da passiert?
> >
> > Welche Information fehlt Dir, um es als «Fehler» zu erkennen?
>
> Die Information, wo genau im Quelltext der Fehler steht.

Das hatten wir doch bereits ermittelt.

> Nichtsdestotrotz beschreibt der Quelltext dann immer noch nicht das
> Verhalten der Software.

Doch. Er beschreibt aber zB nicht, was in einer konkreten
C-Implementierung bei Zugriffen über ungültige Zeiger geschieht,
Stichwort 'vaxocentrism'.

> > Solange. Falls Du welche meinst, die das Programm letal an der
> > Funktion hindern würde ich 2? Tage zum Schreiben veranschlagen und
> > einen, um das Resultat in einen Zustand zu bringen, in dem es seine
> > Hauptfunktionen zuverlässig erfüllt.
>
> Es ging hier um korrekte Programme. Ein Programm, was nicht alle
> Funktionen richtig erfuellt, ist nicht korrekt.

Ein offensichtlich einleuchtender Allgemeinplatz ohne Bezug.

> Was habe ich gestern erst gelesen: "It is considerably harder to
> write correct programs than programs that are 'supposed to work'".

... and this is a dangerous error: It's considerably more effort.

Die Annahme, man könne 'korrekte Programme' (falls man das Glück hat,
überhaupt angeben zu können, was 'korrekt' heißt) qua Kopfgeburt
'schreiben' ist blanker Irrsinn. Immer noch.

> >> Toll. Klasse. Dein Nachfolger dann auch.
> >
> > Das ist zum Glück nicht mein Problem.
>
> Fuer diesen Satz wuerdest Du bei mir rausfliegen. Fristlos und ohne
> Abfindung.

Ich schreibe keine Bibliotheken, dh auch keinen Code, der
in einem beliebigen anderen Kontext 'wiederverwendbar' sein soll.

> Das ist genau *das* Problem im Lebenszyklus einer Software, die
> laenger als 3 Tage eingesetzt werden soll.

Nein, das ist das Problem im Lebenszyklus einer Firma, die mit
möglichst geringem Aufwand große Einnahmen haben möchte: 'Wie kann ich
unser altes Programm von für fünf Jahren so aufbohren, daß wir es
möglichst unverändert weiterverwenden können.' Da kommt dann nach
kurzer Zeit der allseits bekannte unwartbare Klumbatsch bei raus, zzgl
Todesopfer.

Es ist mir in den zwei Jahren, in denen ich 'hier' wohne, nicht
untergekommen, daß ich anderer Leute Code hätte verwenden können, ohne
irgendwann im Quellcode entweder Fehler zu verbessern oder bloß
zu ergründen, wie die Dokumentation gemeint war. Falls 'rationale
Softwareproduktion' ('ökonomisches Prinzip') nicht das primäre Problem
ist, würde ich von 'Wiederverwendung' dringend abraten.

> > O(1) heißt «Es gibt einen Konstante, die größer ist, als alle real
> > vorkommenden Werte» und nicht «Ich verbrauche eine im Vorraus exakt
> > spezifizierte Speichermenge».
>
> O(1) heisst, ich brauche eine konstante (und berechenbare)
> Speichermenge.

Wie anderswo ausgeführt, ist das ein Irrtum: Big-Oh macht Aussagen
über Verhalten von Algorithmen für unterschiedliche große Mengen von
Eingabedaten in Form der Natur einer oberen Schranke. f(n) <= c * g(n)
für O(g). O(1) bedeutet, g(n) = x (konstant) für alle n.

> > Du iterierst über einen Zahlenbereich, ohne dazu Vergleiche mit der
> > relevanten Bereichsgrenze anzustellen?
>
> Ueberlaufpruefung und Bereichsvergleiche sind durchaus etwas anderes.
>
> Im Unterschied zu Deinem Code kann ich Dir aber sagen, dass die Schleife
> irgendwann verlassen wird. Was macht Deine Schleife, wenn sie keinen
> Endemarker findet?

Dann ist das System leider kaputt und als armes userspace-Programm
sind mir da ein wenig die Hände gebunden.

> >> Das was Du dort benutzt hast, war ein Array auf irgendwelche
> >> Strukturen,
> >
> > Falsch.
>
> "p++" impliziert hier pointer-Arithmetik auf einer Array-Struktur.

Verständnisfehler meinerseits ('struct').

> Ich brauche so selten Pointer, weil ich mit "in/out" schaetzungsweise
> ca. 90% dessen abgedeckt habe, wozu man in C Zeiger braucht.

Dann irrst Du Dich sehr kräftig. '90%' der Zeiger in C fungieren als
Iteratoren oder Elemente verketteter Datenstrukturen.

Vinzent Hoefler

unread,
Jan 30, 2003, 1:22:00 PM1/30/03
to
Rainer Weikusat wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Rainer Weikusat wrote:
>> > Genau das steht da oben: Falls man bestimmte Möglichkeiten außer
>> > acht läßt, ist das Modell gültig.
>>
>> Deswegen verifiziert man den Objekt-Code, compiliert trotz "proof of
>> absence of runtime errors" *mit* Runtimechecks und baut Compiler, die
>> *jeden* Speicherzugriff zweimal checken.
>
> ... und das Programm tut immer noch nicht, was es soll, weil der
> Programmierer die Spezifikation aus Zeitdruck partiell ignoriert hat.

Und? Das kann Dir immer und ueberall passieren. In SPARK koennte es
schwieriger werden, da es ja moeglich ist, dass Du es einfach nicht
schaffst, den Examiner zu ueberzeugen, dass Deine falsche
Implementierung die Spezifikation doch erfuellt.

>> Dazu baut man redundante Systeme in Hardware, selbstredend keine
>> identische Kopien der Software.
>
> Falls man gelten läßt, daß 'mehr Code' 'mehr unentdeckte Fehler'
> bedeutet, hat man die Zuverlässigkeit des Gesamtsystems dadurch
> erfolgreich vermindert.

Das rechnest Du mir vor:

-- 8< --
Zwei nicht identische Systeme A und B sollen eine Ausfallrate von 10**-4
/ h haben. Beide Systeme sind nicht gleichberechtigt, d.h. System B
(Slave) wird erst im Falle des Ausfalls von System A (Master)
aktiviert.

Berechne die durchschnittliche Anzahl von Stunden, bevor es

a) in einer Umgebung mit ausschliesslich einem Master oder einem Slave
b) in einer Umgebung mit Master und Slave

zu einem Totalausfall kommt.
-- 8< --

Im allgemeinen geht es dabei darum, dass System A nicht im Falle des
Ausfalls die Kontrolle an System B abgibt, welches dann aufgrund
gleichen Designs genauso ausfaellt, weil es mit den gleichen
Eingangsdaten rechnet wie System A.

Die Wahrscheinlichkeit, dass der gleiche Fehler auch im Backup-System
auftritt, ist verringert.

> Elektronik kann ausfallen.

Deswegen ist die auch redundant. Mehr Elektronik

> Software nicht.

Ach nein? Die Software bei der ersten Mondlandung *ist* ausgefallen,
weil sie sich wegen Speichermangel (zu viele Eingangsdaten) abgeklemmt
hat.

Ariane 5 ist auch ein schoenes Beispiel, dass in diesem speziellen Fall
auch ein dritter oder vierter Backup-Computer mit der gleichen Software
exakt nichts gebracht haette.

> Weil dann auch nicht gesichert ist, daß
>
> for (i = 0; i < 10; ++i)
>
> nicht bereits zu
>
> for (j = -1; j > -2; j *= 15)
>
> mutiert ist oder zu jedem beliebigen Zeitpunkt dazu mutieren könnte,
> dürfen wir jeglichen Versuch, Aussagen über Verhalten von Maschinen
> zu machen, als weltfremdes Hirngespinst ad acta legen.

Sag ich doch. Haeltst Du das fuer praktikabel?

>> Was ist Dein Argument? Weil es gewisse Fehlerquellen gibt, die man
>> nicht ausschliessen kann, kann man alle anderen Fehlerquellen auch
>> drin lassen, es bringt ja ohnehin nichts?
>
> Ja. Es bringt Dir als Implementierer etwas, falls es Dir Arbeit
> abnimmt.

Richtig.

> Sonst niemandem.

Nicht ganz. Dahinter steckt auch die Idee, dass bei gleichem
Arbeitsaufwand das endgueltige System fuer den Nutzer sicherer ist,
weil man das Aufwand/Nutzen-Verhaeltnis verbessern konnte.


Vinzent.

--
Why is it that there are so many more horses' asses than there are
horses?
-- G. Gordon Liddy

Vinzent Hoefler

unread,
Jan 30, 2003, 1:59:56 PM1/30/03
to
Rainer Weikusat wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> Rainer Weikusat wrote:
>> > Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> >> Kommt mir absolut nicht so vor, da Du offensichtlich formale
>> >> Methoden ablehnst und Dir der Quelltext als Erkenntnis fuer das
>> >> korrekte Arbeiten des Programms offensichtlich vollkommen
>> >> ausreichend erscheint.
>> >
>> > Mehr gibts nunmal nicht.
>>
>> Doch. Eine Dokumentation.
>
> Mit Glück. Und vielleicht sogar eine zutreffende.

Das ist zuminest das, woran ich auch arbeite.

>> > Außer Spinnereien, versteht sich.
>>
>> Klar. Kommentare sind auch unnoetig, steht ja alles im Quelltext?
>
> Kommentare stehen auch im Quelltext. Aber grundsätzlich ist das
> richtig: Die meisten Kommentare [die ich kenne] sind überflüssig,
> denn Leute haben einen notorischen Hang dazu, den Code zu
> 'kommentieren' anstatt ihn zu erläutern.

Offensichtlich kennst Du die selben Leute wie ich. Was hast Du also nun
dagegen, wenn ich unkommentierte Typen wie

|type Timer is range 2 .. 65535;

hinwerfe, waehrend Deine (zugehoerige ) Funktion nur:

|unsigned int clamp_timer(double value)

hinklatscht?

Nein, bei mir bliebe auch obiges nicht unkommentiert, aber es waere um
selbst im angenommenen worst-case noch um Groessenordnungen
selbsterklaerender.

>> Nichtsdestotrotz beschreibt der Quelltext dann immer noch nicht das
>> Verhalten der Software.
>
> Doch. Er beschreibt aber zB nicht, was in einer konkreten
> C-Implementierung bei Zugriffen über ungültige Zeiger geschieht,
> Stichwort 'vaxocentrism'.

Was nun? Beschreibt der Quelltext nun das Verhalten der Software
*vollstaendig* oder nicht?

>> Was habe ich gestern erst gelesen: "It is considerably harder to
>> write correct programs than programs that are 'supposed to work'".
>
> ... and this is a dangerous error: It's considerably more effort.

Meinetwegen.

> Die Annahme, man könne 'korrekte Programme' (falls man das Glück hat,
> überhaupt angeben zu können, was 'korrekt' heißt) qua Kopfgeburt
> 'schreiben' ist blanker Irrsinn. Immer noch.

Nein. Einige Erfahrungen aus ca. 20KSLOC-Programmen in SPARK lehren,
dass das gehen kann. It ran the first time.

Gut, natuerlich kann man nun die Einschraenkung bringen, dass ein
Programm nur solange korrekt sei, bis man den ersten Fehler gefunden
hat.

>> >> Toll. Klasse. Dein Nachfolger dann auch.
>> >
>> > Das ist zum Glück nicht mein Problem.
>>
>> Fuer diesen Satz wuerdest Du bei mir rausfliegen. Fristlos und ohne
>> Abfindung.
>
> Ich schreibe keine Bibliotheken, dh auch keinen Code, der
> in einem beliebigen anderen Kontext 'wiederverwendbar' sein soll.

Darf man fragen, was Du fuer Einwegprogramme schreibst?

>> Das ist genau *das* Problem im Lebenszyklus einer Software, die
>> laenger als 3 Tage eingesetzt werden soll.
>
> Nein, das ist das Problem im Lebenszyklus einer Firma, die mit
> möglichst geringem Aufwand große Einnahmen haben möchte: 'Wie kann ich
> unser altes Programm von für fünf Jahren so aufbohren, daß wir es
> möglichst unverändert weiterverwenden können.'

Das ist blanker Unsinn. Man moechte auch ein kleines 40 KLOC-Programm
nicht jedesmal neu schreiben, wenn sich an der Hardware oder am
Interface zu externer Software etwas aendert.

Wenn Du das tun wuerdest, koenntest Du Dir einen grossen Teil der Arbeit
mit Programmdesign und Modularisierung etc. sparen.

> Da kommt dann nach
> kurzer Zeit der allseits bekannte unwartbare Klumbatsch bei raus, zzgl
> Todesopfer.

Todesopfer muss ich zum Glueck nicht befuerchten.

> Es ist mir in den zwei Jahren, in denen ich 'hier' wohne, nicht
> untergekommen, daß ich anderer Leute Code hätte verwenden können, ohne
> irgendwann im Quellcode entweder Fehler zu verbessern oder bloß
> zu ergründen, wie die Dokumentation gemeint war.

Kommt mir bekannt vor. Deswegen kann ich trotzdem nicht alles komplett
neu schreiben. Ich kann lesen, ich kann Fehler erkennen und ich kann
sie fixen.

> Falls 'rationale
> Softwareproduktion' ('ökonomisches Prinzip') nicht das primäre Problem
> ist, würde ich von 'Wiederverwendung' dringend abraten.

Das ist es aber in den meisten Faellen. Sonst muesste man ja nicht
dokumentieren, kommentieren o.ae. Schliesslich weiss man selbst ja, was
man tut und kennt eventuell die Beschraenkungen gewisser Funktionen.

Und wenn man mal was aendern muss, wuerde man es ja ohnehin neu
schreiben. Nein, so funktioniert das eben nicht.

>> > O(1) heißt «Es gibt einen Konstante, die größer ist, als alle real
>> > vorkommenden Werte» und nicht «Ich verbrauche eine im Vorraus exakt
>> > spezifizierte Speichermenge».
>>
>> O(1) heisst, ich brauche eine konstante (und berechenbare)
>> Speichermenge.
>
> Wie anderswo ausgeführt, ist das ein Irrtum: Big-Oh macht Aussagen
> über Verhalten von Algorithmen für unterschiedliche große Mengen von
> Eingabedaten in Form der Natur einer oberen Schranke. f(n) <= c * g(n)
> für O(g). O(1) bedeutet, g(n) = x (konstant) für alle n.

Fuer einen gegebenen implementationsfaehigen Algorithmus sollte man x
aber berechnen koennen. Ich wuesste sonst nicht ganz, wie man auf die
Aussage O(1) kommen koennen sollte.

>> Im Unterschied zu Deinem Code kann ich Dir aber sagen, dass die
>> Schleife irgendwann verlassen wird. Was macht Deine Schleife, wenn
>> sie keinen Endemarker findet?
>
> Dann ist das System leider kaputt und als armes userspace-Programm
> sind mir da ein wenig die Hände gebunden.

Richtig. Es ist kaputt. Es passieren Fehler. Du verlaesst Dich also
durchaus darauf, dass andere das tun, was sie behaupten zu tun. Im
gegebenen Beispiel waere die for-Schleife im Prinzip also sicherer im
Hinblick darauf, dass das ganze nicht in eine Endlosaktion oder einen
Segfault ausartet.

>> >> Das was Du dort benutzt hast, war ein Array auf irgendwelche
>> >> Strukturen,
>> >
>> > Falsch.
>>
>> "p++" impliziert hier pointer-Arithmetik auf einer Array-Struktur.
>
> Verständnisfehler meinerseits ('struct').

Fuer meine Begriffe war das ein Array mit einem Elementtyp einer
Struktur. Klarer? Mittels "++p" (schriebst Du wohl) bist Du zum jeweils
naechsten Element gewandert. Fuer mich ist das erst einmal ein Array,
ein Zugriff via p[i] sollte rein technisch ja genauso funktionieren.

>> Ich brauche so selten Pointer, weil ich mit "in/out" schaetzungsweise
>> ca. 90% dessen abgedeckt habe, wozu man in C Zeiger braucht.
>
> Dann irrst Du Dich sehr kräftig. '90%' der Zeiger in C fungieren als
> Iteratoren oder Elemente verketteter Datenstrukturen.

Da irrst Du Dich aber mit ziemlicher Sicherheit auch. Schon ein
einfaches printf () benutzt doch explizit Pointer. Ich gebe ja durchaus
zu, dass die von mir empfundenen 90% moeglicherweise etwas uebertrieben
waren. Aber wenn ich mir in einem durchschnittlichen C-Programm die
vielen "*" und "&" in Funktionsdeklarationen und -aufrufen so
betrachte, machen die durchaus einen recht grossen Anteil aus.
Jedenfalls sehe ich das subjektiv oefter als ein "->".


Vinzent.

--
Kill a commie for Christ!

Vinzent Hoefler

unread,
Jan 30, 2003, 3:34:35 PM1/30/03
to
Rainer Weikusat wrote:

> NB: Der konkrete Aufwand ist für jeden Programmdurchlauf konstant,
> allerdings *weder*
>
> - zwangsläufig von vorneherein bekannt
> - für jeden durchlauf identisch

Aha, offensichtlich willst Du darauf hinaus, dass der Aufwand nicht
konstant (unabhaengig von der Anzahl der Elemente), sondern - durch
eine Konstante bestimmt - auch nur *maximal* sein kann.

> Falls Du noch ein Codebeispiel dafür brauchst, laß es mich bitte
> wissen. Kurz sieht das so aus:
>
> a) es gibt maximal n Eingabedatenpakete, für die gleichzeitig
> Platz belegt wird
>
> b) diese n Eingabedatenpakete zerfallen in Einheiten zu m
> Paketen (mit m variabel und <= n), für die ich wiederum
> «bestimmte Verwaltungsdaten» benötige.
>
> Offensichtlich ist a O(1) und b O(n), aber wegen m <= n ist die
> Gesamtmenge ebenfalls nach oben durch eine Konstante limitiert,
> konkret maximal 4096a + maximal 4095b.

Somit ist das ein maximaler Speicheraufwand, unabhaengig von der
konkreten Zahl der Elemente. Es gehoert damit aber zu O(1), da es
unabhaengig von der Anzahl der Elemente ist, wenn diese durch ein
Maximum beschraenkt ist. Zugegeben, etwas gewoehnungsbeduerftig, da man
ja normalerweise n als unbeschraenkt ansieht.

> Die konkrete Menge für den
> zweiten Anteil hängt von der internen Strukur der Eingabedaten ab,
> *NICHT* ihre Obergrenze.

Ja.

Der Speicheraufwand ist doch offensichtlich n_max + m_max, nach Deinen
obigen Angaben also in etwa so:

aus a) ergibt sich konkret: n_max = 4096 * x
und aus b) dann, wenn m=n : m_max = n_max * n_max * y

x, y sind der jeweils konkrete Speicheraufwand fuer die Verwaltung, etc.
Was genau an (4096 * x + (n_max**2) * y) ist nicht konstant, wenn
n_max, x und y konstant sind?

Wenn ich n_max allerdings entgegen Deiner Aussage nicht als Konstante
annehme (was man ja normalerweise bei solchen Betrachtungen auch nicht
macht), waere das ganze tatsaechlich ein O(n**2) fuer mich und in SPARK
ohne konkrete Groessenbeschraenkung nicht moeglich.

Wenn man die maximale Anzahl der Elemente aber begrenzt, sind somit in
SPARK auch Algorithmen moeglich, die einen Speicheraufwand groesser
O(1) haben, wenn man dann dort eine konkrete obere Schranke angeben
kann. Besser?

Aber mal ganz konkret: Welcher terminierende Algorithmus haette in
diesem Sinne dann *kein* O(1)-Verhalten, wenn die maximale Anzahl der
bearbeiteten Elemente nach oben beschraenkt ist? Offensichtlich gilt ja
dann immer irgendeine konkrete Inkarnation von O(n_max).


Vinzent.

--
Absinthe makes the tart grow fonder.

Lutz Donnerhacke

unread,
Jan 30, 2003, 4:12:20 PM1/30/03
to

Stevens kenne ich ausreichen, um zu wissen, daß diese Routine mit -1 und
errno = EINTR abbechen wird. Oder eben mit rc != datalen.

Vinzent Hoefler

unread,
Jan 30, 2003, 9:03:37 PM1/30/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> wrote:

>Das wäre ein extrem simplifiziertes Beispiel. Ich hatte eher an eine
>Menge von Programmen und Hardware gedacht, die interagieren. Den
>Zustand dieses «Systems» kann ich nicht aus einem Programmquelltext
>ergründen (und auch nicht aus allen, es fehlen wechselseitige
>Einflüsse), aber falls ich ein paar vereinfachende Annahmen mache,
>kann ich Aussagen über das Verhalten des Programmes machen, solange
>diese Annahmen zutreffen. Nichts anderes tut ein Beweis.

Das interessante daran ist, dass SPARK solche Aussagen mit relativ
wenigen Annahmen machen kann (natuerlich nicht fuer ein
Multitasking-System, in dem das aus dem zu pruefenden Quelltext zu
erstellende Programm nur ein kleiner Bestandteil ist).
Eine dieser wenigen Annahmen (die in gewisser Weise gefaehrlich
waeren, wenn man sich ausschliesslich auf SPARK verlassen wuerde) ist:

"The outside world [Hardware-Register, Sensoren, etc. (Anm. d. A.)] is
always initialized."

SPARK erlaubt auch einfach einige Dinge nicht, ueber die keine
gesicherten Aussagen machen kannst, ohne die exakten
Implementierungsdetails zu kennen.

Dadurch gibt es in SPARK weder Fehler durch Funktionen, die
Seiteneffekte haben (was z.B. Abhaengigkeiten von der Reihenfolge des
Aufrufs haben kann) noch durch Parameter-Aliasing. Und allein das nur
anhand des Quelltextes programmweit nachzuweisen, indem Du saemtliche
moeglichen Parameter und referenzierten Variablen durchgehst, ist mehr
als nur schwierig.

Im Tutorial gab es da gleich am Anfang ein kleines huebsches Beispiel:

|A : Vector(1 .. 1);
|
|procedure P(V : Vector)
|is
|begin
| A(1) := V(1) + V(1);
| A(1) := A(1) + A(1);
|end;
| ....
|A(1) := 1.0;
|P(A);
|
|o If parameter is passed by copying, the final value of A(1) is 3.0.
|o If parameter is passed by reference, the final value of A(1) is 4.0.
|
|o Using SPARK, this insecurity is detected:
|
|procedure P(V : Vector)
|--# global A;
|--# derives A from V;
|is
|begin
| A(1) := V(1) + V(1);
| A(1) := A(1) + A(1);
|end;
| ....
|A(1) := 1.0;
|P(A);
| ^
|*** Semantic Error : This parameter is overlapped by an
| exported global variable.
|

Ich bin mir nicht sicher, dass ich solche Art von Problemen, die sich
in der Praxis ueber mehrere Aufrufebenen erstreckend koennen, immer
auf Anhieb feststellen wuerde.

In jedem Fall kannst Du solche Fehler damit sehr zeitig feststellen
und beseitigen, bevor Du ueberhaupt wegen unerwartetem Verhaltens zum
Debugger greifen und die Funktionsaufrufe und Variablen tracen musst.

Noch kurz ein Zitat:

|Control-flow analysis reveals
| - unreachable or "dead" code,
| - code from which no exits are accessible,
| - "badly-structured code", e.g. multiple-entry loops.
|
|Data-flow analysis reveals
| - conditional or unconditional use of undefined variables,
| - unused variable definitions,
| - loop-invariant definitions and redundant tests

BTW, dort ist die eigentlich semantische Analyse (sprich: der Prover)
noch gar nicht aktiv. Den sollte man ohnehin ueber Nacht laufen
lassen.

Es geht einfach darum, Fehler fruehzeitig zu erkennen und zu
beseitigen. Genau das *kann* SPARK leisten, wenn man es richtig
einsetzt. Was genau hast Du dagegen?


Vinzent.

Rainer Weikusat

unread,
Jan 31, 2003, 4:12:34 AM1/31/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Offensichtlich kennst Du die selben Leute wie ich. Was hast Du also nun
> dagegen, wenn ich unkommentierte Typen wie
>
> |type Timer is range 2 .. 65535;
>
> hinwerfe, waehrend Deine (zugehoerige ) Funktion nur:
>
> |unsigned int clamp_timer(double value)
>
> hinklatscht?

*Mir* ist das vollkommen egal. Aufgrund von «Umständen» benutze ich zZt
fast ausschließlich typlose oder schwach typisierte Sprachen und das
geht halt auch ganz gut. Der Vorteil, der mir im Moment einfiele,
wäre der, daß das, was dabei herauskommt, weniger 'Ballast' in Form
von Artefakten der Programmiersprache, die zur Modellierung
abstrakter Lösungen für inhärente Programmierprobleme verwendet
werden, enthält: Der Code hat erkennbar mehr mit dem Problem zu tun,
das er lösen soll, als mit seiner eigenen Binnenstruktur. Bei einem
'durchschnittlichen' (Unix-)Programm (dh deutlich weniger als 15.000
Zeilen) habe ich bis jetzt eher 'abstrakte' Deklarations-Drahtverhaue
anstelle praktischer Vorteile gefunden (falls ich zum Verständnis von
zehn Zeilen Code erst eine komplette Klassenhierarchie entziffern
muß, behindert mich das eher).

> Nein, bei mir bliebe auch obiges nicht unkommentiert, aber es waere um
> selbst im angenommenen worst-case noch um Groessenordnungen
> selbsterklaerender.

case 0xe0: /* video */
tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
if (tmp2 > end)
goto copy;
if ((buf[6] & 0xc0) == 0x80) { /* mpeg2 */
mpeg2_flag = 1;
if (buf[7] & 0x80) { /* pts */
pts = ((buf[9] & 0x0E) << 29) |
((buf[10]) << 22) |
((buf[11] & 0xFE) << 14) |
(buf[12] << 7) |
(buf[13] >> 1);
dfprintf(stderr, "pts %x\n", pts);
}
if (buf[7] & 0x40) { /* dts */
dfprintf(stderr, "dts\n");
}
if (buf[7] & 0x10) {
dfprintf(stderr, "es rate\n");
}
tmp1 = buf + 9 + buf[8];
} else { /* mpeg1 */
mpeg2_flag = 0;
for (tmp1 = buf + 6; *tmp1 == 0xff; tmp1++)
if (tmp1 == buf + 6 + 16) {
fprintf(stderr, "too much stuffing\n");
buf = tmp2;
break;
}
if ((*tmp1 & 0xc0) == 0x40)
tmp1 += 2;

if (tmp1[0] & 0x20) {
pts = ((tmp1[0] & 0x0E) << 29) |
((tmp1[1]) << 22) |
((tmp1[2] & 0xFE) << 14) |
(tmp1[3] << 7) |
(tmp1[4] >> 1);
/* fprintf(stderr, "%x\n", pts); */
}

tmp1 += mpeg1_skip_table[*tmp1 >> 4];
}

... und das ist definitiv ein 'eher verständlicher'
Quelltext. Programme, wo in der Spezifkation etwas von 'six
interconnected state machines' steht, die mit >20 globalen Variablen
arbeiten, was dann von irgendwelchen graduate students aus Amiland
wörtlich in C umgesetzt wird, einschließlich eines vollständigen
(und überflüssigen) SSL-handshakes mit Hilfe un- oder
halbdokumentierter OpenSSL-Funktionen und lustigen Kommentaren à la

/*
openssl, poor as the interface is¹,
is nevertheless cool in this respect
*/

1) «Sure that you *found* it?» [d. Red.]

sind um einiges übler. Ich wage nicht, mir vorzustellen, wie sowas
erst in einer Sprache mit einem komplexen Typsystem aussähe (kenne
allerdings ein paar Beispiele dafür :->>).

> > Doch. Er beschreibt aber zB nicht, was in einer konkreten
> > C-Implementierung bei Zugriffen über ungültige Zeiger geschieht,
> > Stichwort 'vaxocentrism'.
>
> Was nun? Beschreibt der Quelltext nun das Verhalten der Software
> *vollstaendig* oder nicht?

Offensichtlich nicht, denn der Computer könnte umfallen und Kontakt zu
einigen Peripherigeräten verlieren. Ich denke, man muß sich da
irgendwo Gedanken um sinnvolle Abgrenzungen zusammenhängender Dinge
voneinander machen: Eine Sprachdefinition impliziert irgendeine
abstrakte Maschine (die bei C eng an eine konventionelle CPU angelegt
ist, also an eine Registermaschine²) mit irgendwelchen definierten
Eigenschaften. Eine Eigenschaft der «C-Maschine» ist, daß sie
«ungültige Zeiger» kennt, von denen sie nur sagt, daß sie nicht
konform dereferenzierbar sind. Das ist das einzige, was ich über den
Effekt von

p = NULL;
printf("%u\n", *p);

weiß, ohne externe Faktoren zu berücksichtigen, dh der konkrete Effekt
auf einem beliebigen realen System ist keine Eigenschaft dieser
Maschine. Falls Du mehr wissen möchtest, mußt Du das in Maschinencode
übersetzen und ermitteln, was der Prozessor Deines Zielsystems damit
anfangen wird. Das steht immer noch im Programmquelltext, nur nicht in
der C-Norm.

2) Wie sich durch Suche nach 'acccumulator machine' oder
'register machine' einfach belegen läßt, wird der Begriff
auch so verwendet. Meinetwegen falsch, aber treffend.

> > Die Annahme, man könne 'korrekte Programme' (falls man das Glück hat,
> > überhaupt angeben zu können, was 'korrekt' heißt) qua Kopfgeburt
> > 'schreiben' ist blanker Irrsinn. Immer noch.
>
> Nein. Einige Erfahrungen aus ca. 20KSLOC-Programmen in SPARK lehren,
> dass das gehen kann. It ran the first time.

... after we got it compiled? Das Verb ist einfach falsch verwendet:
Man schreibt irgendwelche Dateien, in denen sich Teile eines
Programmes befinden, daß man zu erstellen gedenkt. Evtl korrigiert man
die, schreibt sie um, ersetzt sie etc. Es wird sich niemand hinsetzen
und «20K SLOC» 'einfach so' aus dem Kopf herunterschreiben und falls
doch, wird das nicht beim ersten Mal laufen.

> >> Fuer diesen Satz wuerdest Du bei mir rausfliegen. Fristlos und ohne
> >> Abfindung.
> >
> > Ich schreibe keine Bibliotheken, dh auch keinen Code, der
> > in einem beliebigen anderen Kontext 'wiederverwendbar' sein soll.
>
> Darf man fragen, was Du fuer Einwegprogramme schreibst?

Ich bringe Unix-Systeme auf eine «geeignete Art und Weise» dazu, das
sie Dinge tun, die irgendjemand für erstrebenswert hält. Am oberen
Ende sind das 30K(-Maschinencode)-Programme (das war mal groß ;-) mit
ziemlich spezialisierten Aufgaben, die auf Dauerbetrieb ausgelegt sein
müssen, am unteren Portierungen widerlicher Solaris-ksh-Skripte nach
$irgendwas. Nix dolles, aber ganz unterhaltsam.

> >> Das ist genau *das* Problem im Lebenszyklus einer Software, die
> >> laenger als 3 Tage eingesetzt werden soll.
> >
> > Nein, das ist das Problem im Lebenszyklus einer Firma, die mit
> > möglichst geringem Aufwand große Einnahmen haben möchte: 'Wie kann ich
> > unser altes Programm von für fünf Jahren so aufbohren, daß wir es
> > möglichst unverändert weiterverwenden können.'
>
> Das ist blanker Unsinn. Man moechte auch ein kleines 40 KLOC-Programm
> nicht jedesmal neu schreiben, wenn sich an der Hardware oder am
> Interface zu externer Software etwas aendert.

Das ist kein kleines Programm. Im Zweifelsfall: «Kommt darauf
an». Wenn man beliebigen Assemblercode wild zusammenkopiert, baut man
seltsame Maschinen. Ich hatte das auch mehr im Hinblick auf generische
Bibliotheken gemeint: Es lohnt sich nicht, die Kontrollstruktur eines
Programms nach Maßgabe eines unpassenden Interfaces zu vergewaltigen,
um zwanzig Zeilen Code zu sparen, der menschlichem Verständnis dadurch
erheblich zugänglicher wird.

> > Wie anderswo ausgeführt, ist das ein Irrtum: Big-Oh macht Aussagen
> > über Verhalten von Algorithmen für unterschiedliche große Mengen von
> > Eingabedaten in Form der Natur einer oberen Schranke. f(n) <= c * g(n)
> > für O(g). O(1) bedeutet, g(n) = x (konstant) für alle n.
>
> Fuer einen gegebenen implementationsfaehigen Algorithmus sollte man x
> aber berechnen koennen. Ich wuesste sonst nicht ganz, wie man auf die
> Aussage O(1) kommen koennen sollte.

Nicht notwendigerweise ohne Berücksichtigung der Eingabedaten. Es wird
lediglich gesagt, daß der maximale Speicherverbrauch für eine beliebig
große Menge davon sich nicht in Abhängigkeit von der Größe dieser
Menge ändert.

> >> Im Unterschied zu Deinem Code kann ich Dir aber sagen, dass die
> >> Schleife irgendwann verlassen wird. Was macht Deine Schleife, wenn
> >> sie keinen Endemarker findet?
> >
> > Dann ist das System leider kaputt und als armes userspace-Programm
> > sind mir da ein wenig die Hände gebunden.
>
> Richtig. Es ist kaputt. Es passieren Fehler. Du verlaesst Dich also
> durchaus darauf, dass andere das tun, was sie behaupten zu tun. Im
> gegebenen Beispiel waere die for-Schleife im Prinzip also sicherer im
> Hinblick darauf, dass das ganze nicht in eine Endlosaktion oder einen
> Segfault ausartet.

A wise user would rather have a program crash, visibly, than
have it return nonsense without indicating anything might be
wrong.

Die Annahme ist außerdem falsch: In beiden Fällen greift man auf
beliebige hintereinanderliegende Teile das Programmadressraums zu und
irgendwann verläßt man den zwangsläufig.

> >> "p++" impliziert hier pointer-Arithmetik auf einer Array-Struktur.
> >
> > Verständnisfehler meinerseits ('struct').
>
> Fuer meine Begriffe war das ein Array mit einem Elementtyp einer
> Struktur. Klarer?

Nein. Es ist ein char *[].

> >> Ich brauche so selten Pointer, weil ich mit "in/out" schaetzungsweise
> >> ca. 90% dessen abgedeckt habe, wozu man in C Zeiger braucht.
> >
> > Dann irrst Du Dich sehr kräftig. '90%' der Zeiger in C fungieren als
> > Iteratoren oder Elemente verketteter Datenstrukturen.
>
> Da irrst Du Dich aber mit ziemlicher Sicherheit auch. Schon ein
> einfaches printf () benutzt doch explizit Pointer.
> Ich gebe ja durchaus zu, dass die von mir empfundenen 90%
> moeglicherweise etwas uebertrieben waren. Aber wenn ich mir in einem
> durchschnittlichen C-Programm die vielen "*" und "&" in
> Funktionsdeklarationen und -aufrufen so betrachte, machen die
> durchaus einen recht grossen Anteil aus.

Lediglich sind die meisten davon keine Ausgabeparameter. Falls ich mit
'call by value'-Semantik eine struct übergebe, wird eine private Kopie
davon im activation record der Funktion angelegt. Bei

... f(struct s const *p)

entfällt die Kopie. Hauptnutzen von Zeigern ist trotzdem, daß man
verkettete Datenstrukturen damit zusammenhalten und über lineare
Arrays iterieren kann. Mit Listen kann man viele Dinge tun, falls ein
lineares Laufzeitverhalten akzeptabel ist.

Rainer Weikusat

unread,
Jan 31, 2003, 4:25:22 AM1/31/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> > Die konkrete Menge für den
> > zweiten Anteil hängt von der internen Strukur der Eingabedaten ab,
> > *NICHT* ihre Obergrenze.
>
> Ja.
>
> Der Speicheraufwand ist doch offensichtlich n_max + m_max, nach Deinen
> obigen Angaben also in etwa so:
>
> aus a) ergibt sich konkret: n_max = 4096 * x
> und aus b) dann, wenn m=n : m_max = n_max * n_max * y

n_max * (x + y) - y

> Aber mal ganz konkret: Welcher terminierende Algorithmus haette in
> diesem Sinne dann *kein* O(1)-Verhalten, wenn die maximale Anzahl der
> bearbeiteten Elemente nach oben beschraenkt ist?

Die Anzahl der bearbeiteten Elemente ist aber nicht nach oben
beschränkt, bloß der maximale Aufwand zu ihrer Bearbeitung. Das ist
auch kein «korrektes» Programm, weil die äußere Umstände wie
willkürliche Datenformatfehler und undefiniert große «access units¹»
das verhindern.

1) Genaugenommen über Bitraten definiert. Für alles außer
Schieberegistern sind die aber fiktiv und werden
simuliert.

Rainer Weikusat

unread,
Jan 31, 2003, 4:42:30 AM1/31/03
to
Lutz Donnerhacke <lu...@iks-jena.de> writes:
> > Sie schreibt exakt dann zuwenig, falls die Platte voll ist (physisch
> > oder wegen quota) und bricht unter keinen Umständen grundlos
> > ab. Details dazu findest Du in epischer Breite in APUE, S. 275ff.
>
> Stevens kenne ich ausreichen, um zu wissen, daß diese Routine mit -1
> und errno = EINTR abbechen wird. Oder eben mit rc != datalen.

Die Auswirkungen von Signalen auf Funktionen des Unix-Interfaces wird
in SuSv3 (2, ...) definiert. Das kann man sogar online nachlesen.

A characteristic of earlier Unix systems is that if a process
caught a signal while the process was blocked in a «slow»
system call, the system call was interrupted.

An «if the process *caught* a signal» hat sich auch nichts
geändert. Das Problem, daß manche Bibliotheken soetwas undokumentiert
und nichttransparent tun, besteht allerdings.

Georg Bauhaus

unread,
Jan 31, 2003, 4:43:19 AM1/31/03
to
Rainer Weikusat wrote:
> Genau das steht da oben: Falls man bestimmte Möglichkeiten außer acht
> läßt, ist das Modell gültig.

Sie lassen sie nicht ausser Acht, wie in den von dir angegebenen
Artikel nachgelesen werden kann. Im Gegenteil, alles muss anforderungen
genuegen, die nicht einfach unterstellt werden, also auch nicht
ausser Acht gelassen werden.

Stefan Reuther

unread,
Jan 31, 2003, 5:39:01 AM1/31/03
to
Hallo,

Vinzent Hoefler <JeLlyFish...@gmx.net> wrote:


> Rainer Weikusat wrote:
>> Warum hast Du den Teil mit Typen festgelegter Größe
>> übersehen?

> Toll, da hast Du Typen mit festgelegter Groesse, ohne zu wissen, ob die

^^^^^^^^^^^^


> auf der Maschine effizient umgesetzt werden koennen.

^^^^^^^^^

Widerspricht sich das nicht irgendwie? Such dir halt was aus:

"genau 8 Bits um jeden Preis" -> int8_t
"mindestens 8 Bits" -> int_least8_t
"mind. 8 Bits, so schnell wie möglich" -> int_fast8_t

Die letzten beiden sind garantiert vorhanden. Der Profi nimmt
also int_fast8_t und maskiert nochmal mit 0xFF. Der Profi-
Compiler optimiert die Maskierung weg.


Stefan, trotzdem Unterbereichstypen a la Pascal vermissend

Rainer Weikusat

unread,
Jan 31, 2003, 5:43:44 AM1/31/03
to
Georg Bauhaus <sb4...@uni-duisburg.de> writes:
> Rainer Weikusat wrote:
> > Genau das steht da oben: Falls man bestimmte Möglichkeiten außer acht
> > läßt, ist das Modell gültig.
>
> Sie lassen sie nicht ausser Acht, wie in dem von dir angegebenen
> Artikel nachgelesen werden kann.

Warum löscht Du das Zitat und behauptest das Gegenteil von dem, was
drinstand?

Rainer Weikusat

unread,
Jan 31, 2003, 6:05:51 AM1/31/03
to
Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
> Dadurch gibt es in SPARK weder Fehler durch Funktionen, die
> Seiteneffekte haben (was z.B. Abhaengigkeiten von der Reihenfolge des
> Aufrufs haben kann)

Das ist wider so ein fiktives Problem: Wenn jemand Ausdrücke
konstruiert, in denen mehrere nicht-triviale Unterroutinen aufgerufen
werden, ist das essentiell ungeschickt, denn das ergibt schlechter
verständliche Ausdrücke und erschwert es außerdem, den Code zu
debuggen.

Selbst wenn man davon absieht, sehe ich es als «best practice» an, das
'Funktionen' (misnomer) entweder Seiteneffekte haben oder
Rückgabewerte. Dann treten solche Probleme auch nicht auf. (*)

> noch durch Parameter-Aliasing.

Das ist für 'Optimierungen', die den Code umsortieren, relevant und
kann auch manuell angegeben werden («restrict»), falls man das
möchte.

> Und allein das nur anhand des Quelltextes programmweit nachzuweisen,
> indem Du saemtliche moeglichen Parameter und referenzierten
> Variablen durchgehst, ist mehr als nur schwierig.

Etwas wie (*) anhand des Quelltextes nachzuweisen, ist ausgesprochen
simpel.

Welches kranke Hirn schreibt sowas außer zu Demonstrationszwecken?
*schauder*

> |Control-flow analysis reveals
> | - unreachable or "dead" code,

Gibts nicht zufällig.

> | - code from which no exits are accessible,

Dito. Falls ein «exit» «accessible» ist, sobald ein anderes Programm
eine bestimmte Zeichenfolge über einen IPC-Kanal sendet, kann ich mir
nicht mehr vorstellen, was dieser Nachweis bringen soll.

> | - "badly-structured code", e.g. multiple-entry loops.

Mööp. «Red herring». 'Badly structured' ist der code dann, wenn er
nicht mehr der Logik des Problems folgt (sondern zB externen
Richtlinien). «multiple entry»-Schleifen sind selten, aber manchmal
sinnvoll und ich denke, Code wird lesbarer dadurch, daß er möglichst
ohne Umwege das beschreibt, was er tut.

> |Data-flow analysis reveals
> | - conditional or unconditional use of undefined variables,

Das findet jeder Compiler.

> | - unused variable definitions,

Dito. Bei mir ist das allerdings abgestellt, denn ich verwende
Konstrukte, bei denen ich Werte ignorieren möchte.

> Es geht einfach darum, Fehler fruehzeitig zu erkennen und zu
> beseitigen. Genau das *kann* SPARK leisten, wenn man es richtig
> einsetzt. Was genau hast Du dagegen?

Mir würde das persönlich nichts bringen, weil ich solche Fehler
normalerweise nicht mache, dh in den erwähnten «1000 Zeilen»
vielleicht mal einen davon (dafür andere. Aber auch nicht soo
viele) und weil man die auch schnell findet.

Lutz Donnerhacke

unread,
Jan 31, 2003, 6:57:13 AM1/31/03
to
* Rainer Weikusat wrote:
> werden, enthält: Der Code hat erkennbar mehr mit dem Problem zu tun,
> das er lösen soll, als mit seiner eigenen Binnenstruktur. Bei einem
> 'durchschnittlichen' (Unix-)Programm (dh deutlich weniger als 15.000
> Zeilen) habe ich bis jetzt eher 'abstrakte' Deklarations-Drahtverhaue
> anstelle praktischer Vorteile gefunden (falls ich zum Verständnis von
> zehn Zeilen Code erst eine komplette Klassenhierarchie entziffern
> muß, behindert mich das eher).

Was sagst Du dann zu ftp://ftp.iks-jena.de/pub/mitarb/lutz/cdp/ ?
Besonders zur cdp.h?

>> Nein, bei mir bliebe auch obiges nicht unkommentiert, aber es waere um
>> selbst im angenommenen worst-case noch um Groessenordnungen
>> selbsterklaerender.
>

> if ((buf[6] & 0xc0) == 0x80) { /* mpeg2 */
> mpeg2_flag = 1;
> if (buf[7] & 0x80) { /* pts */
> pts = ((buf[9] & 0x0E) << 29) |
> ((buf[10]) << 22) |
> ((buf[11] & 0xFE) << 14) |
> (buf[12] << 7) |
> (buf[13] >> 1);
> dfprintf(stderr, "pts %x\n", pts);
> }
> if (buf[7] & 0x40) { /* dts */
> dfprintf(stderr, "dts\n");
> }
> if (buf[7] & 0x10) {
> dfprintf(stderr, "es rate\n");
> }
> tmp1 = buf + 9 + buf[8];

Gutes Beispiel:
type Mpeg_Version_T is (Version_1, Version_2);
for Mpeg_Version_T use (Version_1 => 1, Version_2 => 2);

type Video_Header is record
mpeg_version : Mpeg_Version_T;
pts, dts, es_rate : Boolean;
end record;

for Video_Header use record
mpeg_version at 6 range 6 .. 7;
pts at 7 range 7 .. 7;
dts at 7 range 6 .. 6;
es_rate at 7 range 3 .. 3;
end record;
...
case buf.mpeg_version is
when Version_2 =>
mpeg2_flag := True;
if buf.pts then
...;
end if;
if buf.dts then
...;
end if;
if buf.es_rate then
...;
end if;
when Version_1 =>
...
end case;

Was ist daran unlesbarer, abgesehen davon, daß es einige Minuten dauert, zu
begreifen, was die Bitschieberrei grade soll?



>> Nein. Einige Erfahrungen aus ca. 20KSLOC-Programmen in SPARK lehren,
>> dass das gehen kann. It ran the first time.
>
> ... after we got it compiled?

Exakt. Der maschinelle Prüfer ist streng.

> Das Verb ist einfach falsch verwendet: Man schreibt irgendwelche Dateien,
> in denen sich Teile eines Programmes befinden, daß man zu erstellen
> gedenkt. Evtl korrigiert man die, schreibt sie um, ersetzt sie etc. Es
> wird sich niemand hinsetzen und «20K SLOC» 'einfach so' aus dem Kopf
> herunterschreiben und falls doch, wird das nicht beim ersten Mal laufen.

Das drei Affen Prinzip hilft nicht gegen Fakten.

Lutz Donnerhacke

unread,
Jan 31, 2003, 6:58:25 AM1/31/03
to

Du hast ziemlich umständlich formuliert, daß Du mir zustimmst, daß Dein Code
fehlerhaft ist.

Lutz Donnerhacke

unread,
Jan 31, 2003, 7:02:40 AM1/31/03
to
* Stefan Reuther wrote:

> Vinzent Hoefler <JeLlyFish...@gmx.net> wrote:
>> Toll, da hast Du Typen mit festgelegter Groesse, ohne zu wissen, ob die
> ^^^^^^^^^^^^
>> auf der Maschine effizient umgesetzt werden koennen.
> ^^^^^^^^^
>
> Widerspricht sich das nicht irgendwie?

Nein. Es gibt diese Typen nur für 8, 16, 32 und 64 bit. Es gibt sie nicht
für 3 bit, für biased Werte etc. pp. Es kann auch sein, daß der Compiler je
nach Bedarf ein und denselben Typ in unterschiedlichen Maschinenworten
unterbringt, weil dies je nach Situation effizienter ist.

> Such dir halt was aus:
>
> "genau 8 Bits um jeden Preis" -> int8_t
> "mindestens 8 Bits" -> int_least8_t
> "mind. 8 Bits, so schnell wie möglich" -> int_fast8_t

4 bit (weil Teil einer Datenstruktur, die in den RAM gemappt wurde).
Wertebereich 5 bis 20. Wobei die 5 durch Nullbits dargestellt werden.

Rainer Weikusat

unread,
Jan 31, 2003, 7:02:59 AM1/31/03
to

Is gut Lutz, geh solange spielen, bis Dir jemand lesen beigebracht
hat und Du imstande bist, koordiniert auf Außenreize zu reagieren.

Rainer Weikusat

unread,
Jan 31, 2003, 7:05:27 AM1/31/03
to

Falls Du

a) mir nicht glaubst
b) Richard W. Stevens nichts glaubst
c) der Spezifikation nicht glaubst

wie wäre es mit einem Testprogramm? Oder gibt es dann mentalen burnout
wegen plötzlichem Realitätskontakt?

Lutz Donnerhacke

unread,
Jan 31, 2003, 7:07:04 AM1/31/03
to
* Rainer Weikusat wrote:
> Vinzent Hoefler <JeLlyFish...@gmx.net> writes:
>> noch durch Parameter-Aliasing.
>
> Das ist für 'Optimierungen', die den Code umsortieren, relevant und
> kann auch manuell angegeben werden («restrict»), falls man das
> möchte.

Restrict PRÜFT nicht, ob Überlappungen auftreten. Es sagt dem Compiler, daß
er bei der Kompilierung davon ausgehen darf, daß keine Überlappungen da sind.
Wird trotzdem mit Überlappungen aufgerufen, ist das Verhalten undefiniert.

In Spark gibt es einen Bummer vom Compiler.

>> Ich bin mir nicht sicher, dass ich solche Art von Problemen, die sich
>> in der Praxis ueber mehrere Aufrufebenen erstreckend koennen, immer
>> auf Anhieb feststellen wuerde.
>
> Welches kranke Hirn schreibt sowas außer zu Demonstrationszwecken?
> *schauder*

Das geschieht viel zu oft. Allein dadurch, daß öfter mal ein Argument
doppelt verwendet wird oder Slices des gleichen Arrays sich überlappen, aber
unterschiedliche Argumente sind. Das, was Dein restrict aussagen will, aber
nicht tut.

>> Es geht einfach darum, Fehler fruehzeitig zu erkennen und zu
>> beseitigen. Genau das *kann* SPARK leisten, wenn man es richtig
>> einsetzt. Was genau hast Du dagegen?
>
> Mir würde das persönlich nichts bringen, weil ich solche Fehler
> normalerweise nicht mache, dh in den erwähnten «1000 Zeilen»
> vielleicht mal einen davon (dafür andere. Aber auch nicht soo
> viele) und weil man die auch schnell findet.

Du bist unser Gott. Wir beten Deine Unfehlbarkeit an. Aber laß uns unseren
Götzen, der uns auf die Finger haut, wenn wir fehlbar sind.

Lutz Donnerhacke

unread,
Jan 31, 2003, 7:08:33 AM1/31/03
to
* Rainer Weikusat wrote:
> Lutz Donnerhacke <lu...@iks-jena.de> writes:
>> Du hast ziemlich umständlich formuliert, daß Du mir zustimmst, daß Dein Code
>> fehlerhaft ist.
>
> Falls Du
>
> a) mir nicht glaubst

Das tue ich tatsächlich nicht.

> b) Richard W. Stevens nichts glaubst

Dem schon. Und der sagt, es wird auch unterbrochen.

> c) der Spezifikation nicht glaubst

Der auch. Und die sagt, es wird auch unterbrochen.

Und Du zitierst das auch noch!

> wie wäre es mit einem Testprogramm? Oder gibt es dann mentalen burnout
> wegen plötzlichem Realitätskontakt?

Wie wäre es, wenn Du Deine Leseschwäche nicht so offen demonstrieren würdest?

Rainer Weikusat

unread,
Jan 31, 2003, 7:55:48 AM1/31/03
to
Lutz Donnerhacke <lu...@iks-jena.de> writes:
> * Rainer Weikusat wrote:
> > werden, enthält: Der Code hat erkennbar mehr mit dem Problem zu tun,
> > das er lösen soll, als mit seiner eigenen Binnenstruktur. Bei einem
> > 'durchschnittlichen' (Unix-)Programm (dh deutlich weniger als 15.000
> > Zeilen) habe ich bis jetzt eher 'abstrakte' Deklarations-Drahtverhaue
> > anstelle praktischer Vorteile gefunden (falls ich zum Verständnis von
> > zehn Zeilen Code erst eine komplette Klassenhierarchie entziffern
> > muß, behindert mich das eher).
>
> Was sagst Du dann zu ftp://ftp.iks-jena.de/pub/mitarb/lutz/cdp/?

«/* Inform about changes in statistics data. */
void inform_about_new_statistics (void);»

Das hier ist ein Schulbeispiel für wirren code:

while(len-- && pc - out < sizeof(out))
pc += snprintf(pc, sizeof(out) - (pc - out),
hex ? ":%02x" : ".%d", *pi++);


remain = sizeof(out);
while (1) {
if (!len) break;

n = snprintf(p, remain, hex ? ":%02x" : ".%d", *pi);
remain -= n;
if (!remain) break;
p += n;

++pi;
--len;
}

> Besonders zur cdp.h?

Die «üblichen Anahmen», insbesondere, daß das Speicherlayout von
Strukturen kein implizites padding enthält etc.

>
> >> Nein, bei mir bliebe auch obiges nicht unkommentiert, aber es waere um
> >> selbst im angenommenen worst-case noch um Groessenordnungen
> >> selbsterklaerender.
> >
> > if ((buf[6] & 0xc0) == 0x80) { /* mpeg2 */
> > mpeg2_flag = 1;
> > if (buf[7] & 0x80) { /* pts */
> > pts = ((buf[9] & 0x0E) << 29) |
> > ((buf[10]) << 22) |
> > ((buf[11] & 0xFE) << 14) |
> > (buf[12] << 7) |
> > (buf[13] >> 1);
> > dfprintf(stderr, "pts %x\n", pts);
> > }
> > if (buf[7] & 0x40) { /* dts */
> > dfprintf(stderr, "dts\n");
> > }
> > if (buf[7] & 0x10) {
> > dfprintf(stderr, "es rate\n");
> > }
> > tmp1 = buf + 9 + buf[8];
>
> Gutes Beispiel:

für schlechten Code. Man kann das auch in C erheblich durchsichtiger
formulieren.

als beispielsweise:

switch (MPEG_EXT_ID(pq_pos.pos)) {
case MPEG_SEXT_ID:
is_mpeg2 = 1;
len = MPEG_SEXT_LEN;

break;

case MPEG_SDEXT_ID:
len = MPEG_SDEXT_LEN;
if (MPEG_SDEXT_COLOR(pq_pos.pos)) len += MPEG_SDCOLOR_LEN;

break;


> > Das Verb ist einfach falsch verwendet: Man schreibt irgendwelche Dateien,
> > in denen sich Teile eines Programmes befinden, daß man zu erstellen
> > gedenkt. Evtl korrigiert man die, schreibt sie um, ersetzt sie etc. Es
> > wird sich niemand hinsetzen und «20K SLOC» 'einfach so' aus dem Kopf
> > herunterschreiben und falls doch, wird das nicht beim ersten Mal laufen.
>
> Das drei Affen Prinzip hilft nicht gegen Fakten.

Nur, falls man «Ada» für eine faktische Notwendigkeit hält: Da braucht
man eine Menge flotter Sprüche ohne Sinn, die wie Begründungen
aussehen.

Rainer Weikusat

unread,
Jan 31, 2003, 8:09:27 AM1/31/03
to
Lutz Donnerhacke <lu...@iks-jena.de> writes:
> * Rainer Weikusat wrote:
> > Lutz Donnerhacke <lu...@iks-jena.de> writes:
> >> Du hast ziemlich umständlich formuliert, daß Du mir zustimmst, daß Dein Code
> >> fehlerhaft ist.
> >
> > Falls Du
> >
> > a) mir nicht glaubst
>
> Das tue ich tatsächlich nicht.
>
> > b) Richard W. Stevens nichts glaubst
>
> Dem schon. Und der sagt, es wird auch unterbrochen.

"[...] if the process *C*A*U*G*H*T* a signal".

Das wird auf p.256 ebd wie folgt definiert:

2. Catch the signal. To do this, we tell the kernel to call a
function of ours whenever we want to handle the condition.

> > c) der Spezifikation nicht glaubst
>
> Der auch. Und die sagt, es wird auch unterbrochen.

Die sagt folgendes:

Signal Effects on Other Functions

Signals affect the behavior of certain functions defined by
this volume of IEEE Std 1003.1-2001 if delivered to a process
while it is executing such a function.
----------
If the action of the signal is to terminate the process, the
process shall be terminated and the function shall not return.
----------

dh kein EINTR

----------
If the action of the signal is to stop the process, the
process shall stop until continued or terminated. Generation
of a SIGCONT signal for the process shall cause the process to
be continued, and the original function shall continue at the
point the process was stopped.
----------

dh *auch* kein EINTR

----------
Signals that are ignored
shall not affect the behavior of any function;
----------

und hier auch nicht, sondern ausschließlich:

----------
If the action of the signal is to invoke a signal-catching
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
function,
^^^^^^^^
the signal-catching function shall be invoked; in this case the
original function is said to be ``interrupted'' by the
signal. If the signal-catching function executes a return
statement, the behavior of the interrupted function shall be
as described individually for that function, except as noted
for unsafe functions.
----------

Rainer Weikusat

unread,
Jan 31, 2003, 8:20:30 AM1/31/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:
> If the action of the signal is to stop the process, the
> process shall stop until continued or terminated. Generation
> of a SIGCONT signal for the process shall cause the process to
> be continued, and the original function shall continue at the
> point the process was stopped.
> ----------
>
> dh *auch* kein EINTR

Unter Linux gibt es wenigstens für poll allerdings doch eins, aber das
ist kein konformes Verhalten (SunOS und BSD handhaben das anders).

F'up2p weil off topic

Lutz Donnerhacke

unread,
Jan 31, 2003, 8:25:31 AM1/31/03
to
* Rainer Weikusat wrote:
> Lutz Donnerhacke <lu...@iks-jena.de> writes:
>> * Rainer Weikusat wrote:
>> > Lutz Donnerhacke <lu...@iks-jena.de> writes:
>> >> Du hast ziemlich umständlich formuliert, daß Du mir zustimmst, daß Dein Code
>> >> fehlerhaft ist.
>> >
>> > Falls Du
>> >
>> > a) mir nicht glaubst
>>
>> Das tue ich tatsächlich nicht.
>>
>> > b) Richard W. Stevens nichts glaubst
>>
>> Dem schon. Und der sagt, es wird auch unterbrochen.
>
> "[...] if the process *C*A*U*G*H*T* a signal".

Ich weiß. Aber diese Loggerfunktion wird in einem größern Stück Code
verwendet, der sicher Signale abkann, sonst wäre dieser Loggercode sinnlos.
Schließlich will man mit Loggerfunktionen in Daemonen arbeiten, und die
möchte man mit Signalen steuern. Es kann natürlich auch sein, daß diese
Funktion nur für Nichtdaemons spezifiziert ist und der Gebrauch von signal.h
in der README untersagt ist. Aber das wäre eine ziemlich sinnfreie
Implemenation.

It is loading more messages.
0 new messages