GOTO ist einfach cool:
if (error)
goto exit_error;
Viel lesbarer als der ganze Kram wie
if (0 != error)
{
error_bullshit = true;
}
if (error_bullshit != true)
{
do_secure_stuff();
}
Bää..
Seh ich auch so. Richtig verwendet kann goto die Codekomplexität
drastisch reduzieren und die Lesbarkeit des Codes massiv erhöhen.
Viele der selbsternannten Codstylegurus sind jedoch zu borniert, um
das zu kapieren.
Wer denkt sich bloß so einen Bödsinn aus?
? (mehr als 1000 Beiträge seit 26.09.01)
"Rule 57 (required)
The continue statement shall not be used."
Da wird´s doch lächerlich...
Was hat das bitte mit
- embedded
- Sicherheit oder
- automotive
zu tun?
Antwort: Nichts... Da geht´s wohl eher um Gesinnung...
Aber sobald irgendwer sowas als Standard bezeichnet
und Automotive draufschreibt kommt garantiert irgendein
Entscheider bei VW oder einem der Zulieferer
zu der Erkenntnis: Dass muss ja was dran sein...
selber denken ist dann nicht mehr nötig.
Re: Wer denkt sich bloß so einen Bödsinn aus?
omniscient (mehr als 1000 Beiträge seit 26.09.01)
Christian Stieber schrieb am 30. April 2013 15:04
> omniscient schrieb am 30. April 2013 14:52
>
> > "Rule 57 (required)
> > The continue statement shall not be used."
> >
> > Da wird´s doch lächerlich...
> > Was hat das bitte mit
> > - embedded
> > - Sicherheit oder
> > - automotive
> > zu tun?
>
> Direkt erstmal nichts,
Schön.
> aber darum geht es auch garnicht.
Doch darum geht´s. Denn die MISRA
Regeln sollen genau diesem zweck dienen.
Tun sie das aber nicht, wie du zutreffend
bemerkst, sind sie unsinnig.
> Man hat halt
> einen Richtlinienkatalog; den hätte auch der Verband der
> Waschmaschinenhersteller rausbringen können.
Eben es sind Gesinnungsregeln.
> Mit Sicherheit hat es wie meistens durchaus zu tun: 'continue'
> (ebenso wie das Gegenstück 'break') sorgt dafür daß eine
> Schleife auf
> "unerwartete" Weise abgebrochen wird.
Ein break ist ebensowenig wie ein continue
"unerwartet". Die kommen nämlich nicht erst
zur Laufzeit in den code sondern sind vom
Programmierer an den dafür wohlbestimmten
Plätzen regelmäßig nach eintritt von vorbestimmten
Nedingungen.
> Das kann insbesondere bei
> komplexeren Schleifen leicht
> die Unlesbarkeit fördern
Eine komplexe schleife ist bereits komblex.
Ein break oder continue mach es nicht unlesbarer
sondern deren Vermeidung führt zu gestelzten
Konstrukten, die gerade die Lesbarkeit verschlechtern.
> und somit
> leichter fehlerhaften Code nach sich ziehen.
Das ist Quatsch mit Soße... Da
ist keinerlei Kausalzusammenhang.
Re: Doch Blödsinn
ylai (mehr als 1000 Beiträge seit 11.05.01)
EinmalMitProfisArbeiten schrieb am 1. Mai 2013 01:10
> target[j++] = src[i];
Ich bin recht sicher, dass das nicht "legal" nach MISRA ist. Die
Inkrementierung muss eine separate statement haben.
> Aber nehmen wir einmal an, das continue wäre an dieser Stelle
> wirklich realistisch und sinnvoll. Dann führen Regeln wie die in
> MISRA-C nur dazu, dass Programmierer sich irgendeinen Workaround
> ausdenken.
MISRA ist nur teilweise sinnvoll (wie die 1:1 aus Scott Meyers Bücher
übernommene Regeln). Der Rest ist aber pervers, in dem sie sichtlich
C/C++ zu etwas zwischen BASIC und Ada kastrieren will.
Es gibt keine "intrinsische Sicherheit".
? (mehr als 1000 Beiträge seit 31.08.11)
Auch mit dem besten Ruleset nicht. Den Therac-25-Fehler könnte man
problemlos MISRA-kompatibel gestalten.
Re: Wunschdenken: intrinsisch sicheres C(++)
Trollplonk (mehr als 1000 Beiträge seit 02.06.03)
NeoBoot schrieb am 30. April 2013 14:54
> Ich bin mir verdammt sicher, dass es ein Traum bleiben wird. Aber
> angenommen, die MISRA-Regeln würden in den C und C++ Standard
> aufgenommen. Angenommen, der Compiler würde einem, anstatt potentiell
> unsicheren Mist zu kompilieren, lauter Fehler um die Ohren werfen,
> bis der Code endlich garantiert sicher ist. Die Welt wäre ein
> schönerer Ort.
1. Du willst also praktisch eine neue Programmiersprache
entwerfen, in der man keine Denkfehler mehr machen kann.
2. Das ist unmöglich.
3. Am Beispiel PHP sieht man, daß die User so
eine Programmiersprache auch gar nicht wollen.
> Eher erwarte ich aber, dass die µC-Hersteller Rust adoptieren, als
> sowas. Wobei, MISRA unterstützt z.B. die IAR-Toolchain nativ. Leider
Die "Entwicklungswerkzeuge" von IAR Systems zählen
mit zum Schlechtesten, was ich während meiner ganzen
Berufstätigkeit benutzen mußte.
> als schwer kostenpflichtige Zusatzoption. Und Sicherheit als
> Bezahloption ist uncool.
Stimmt, IAR war zwar scheiße, aber wenigstens
teuer und mit Dongle!
Trollplonk
Mein Name ist Programm.
? (3 Beiträge seit 01.05.13)
? schrieb am 30. April 2013 16:59
> Das continue-Statement
> ist eine sehr beliebten Fehlerquelle.
Wenn man das continue-Statement verbietet, führt das nur zu sinnlosen
Workarounds. Statt
while (X) {
if (Y)
continue;
Z;
}
wird dann eben folgendes geschrieben:
while (X) {
if (!(Y)) {
Z;
}
}
So etwas bringt niemanden weiter. continue-Statements sind ein
Symptom eines komplexen Kontrollflusses, und nicht dessen Ursache.
Entsprechend sinnlos ist es, sich von ihrem Verbot eine Verringerung
der Komplexität (und damit der Anzahl der Bugs) zu erhoffen.
Re: Das ist nur die konsequente Umsetzung einer Philosophie.
Arkarit (689 Beiträge seit 02.05.09)
EinmalMitProfisArbeiten schrieb am 1. Mai 2013 02:06
> Garban schrieb am 30. April 2013 16:59
>
> > Das continue-Statement
> > ist eine sehr beliebten Fehlerquelle.
> Wenn man das continue-Statement verbietet, führt das nur zu sinnlosen
> Workarounds. Statt
> while (X) {
> if (Y)
> continue;
> Z;
> }
> wird dann eben folgendes geschrieben:
> while (X) {
> if (!(Y)) {
> Z;
> }
> }
> So etwas bringt niemanden weiter. continue-Statements sind ein
> Symptom eines komplexen Kontrollflusses, und nicht dessen Ursache.
> Entsprechend sinnlos ist es, sich von ihrem Verbot eine Verringerung
> der Komplexität (und damit der Anzahl der Bugs) zu erhoffen.
Genau das ist der Punkt, mit dem unsere "Philosophen" augenscheinlich
hoffnungslos überfordert sind. Ein lokales "goto" und natürlich erst
recht ein "continue" können im richtigen Kontext absolut die Lösung
der Wahl sein. (Ersteres zugegeben sehr selten).
Treten damit Probleme in der Übersichtlichkeit auf, liegt das im
Allgemeinen a) am Kontext selbst, nämlich zu langen Funktionen, zu
hohe Schachtelungstiefe etc. oder b) an der Unfähigkeit des
Programmierers. Wer mit einem "continue" allerdings nicht klarkommt,
wird bei angeordnetem Verzicht darauf trotzdem scheitern und sich -
wie Du richtig schreibst - einen regelkonformen, aber mindestens
ebenso fehlerhaften Workaround zurechtfrickeln.
Und auch im Fall "MISRA" ist es nicht die Sprache, sondern der
Kontext, der Probleme macht. Nicht falsch verstehen, ich liebe C und
C++, aber wenn es um höchste Sicherheitsansprüche geht, kann es
eigentlich nur einen Programmierstandard für diese Sprachen mit einem
einzigen Paragraphen geben:
§1: Nehmt was anderes.
? ? (27 Beiträge seit 26.07.12)
Dieser Schwachsinn erinnert mich an einen früheren Berufsschullehrer.
"Verwenden sie kein break! Break ist für Hacker, aber nicht für
Programmierer."
Vor Fremdschämen wurde es mir beinahe schwarz vor Augen...
? (mehr als 1000 Beiträge seit 16.06.00)
? schrieb am 1. Mai 2013 01:10
> ? schrieb am 30. April 2013 17:28
>
> > Kurzes Beispiel:
> >
> > for(i=0, j=0; src[i];)
> > {
> > if(src[i]<'A' || src[i]>'Z')
> > continue;
> >
> > target[j]=src[i];
> > i++;
> > j++;
> > }
> Das Beispiel überzeugt gleich aus mehreren Gründen nicht. Zum einen
> würde jeder normale Programmierer i im Schleifenkopf inkrementieren
> und nicht im Rumpf:
> for (i = 0, j = 0; src[i]; ++i)
> {
> if (src[i] < 'A' || src[i] > 'Z')
> continue;
> target[j++] = src[i];
> }
> (Ich gehe mal aus, dass der Sinn dieses Codes sein sollte, den String
> zu kopieren und alle Zeichen außer A-Z zu entfernen). Und auch das
> ist nicht realistisch, denn wieso sollte man an dieser Stelle
> überhaupt ein continue verwenden? So ist es viel einfacher:
> for (i = 0, j = 0; src[i]; ++i)
> if (src[i] >= 'A' && src[i] <= 'Z')
> target[j++] = src[i];
>
> Aber nehmen wir einmal an, das continue wäre an dieser Stelle
> wirklich realistisch und sinnvoll. Dann führen Regeln wie die in
> MISRA-C nur dazu, dass Programmierer sich irgendeinen Workaround
> ausdenken. Man würde dann zum Beispiel schreiben
> for(i=0, j=0; src[i];)
> {
> if(!(src[i]<'A' || src[i]>'Z'))
> {
> target[j]=src[i];
> i++;
> j++;
> }
> }
> , und das weist genau den gleichen Fehler auf. Ein Verbot des
> Continue-Statements bringt gar nichts, weil die gleichen Fehler
> einfach auf andere Weise gemacht werden.
Ich bin schockiert, eine korrekte, sachliche und bemühte Antwort. In
den Developer-Foren verspüre ich häufiger das dringende Bedürfnis,
alles in 5 Sekunden abzufackeln und ein Killerkaninchen zur Bewachung
der verbrannten Erde abzustellen... hmm, nein zwei Killerkaninchen
(dann gibt es hoffentlich Nachwuchs ;) - weshalb ich dann oft nicht
reingehe und auch nichts schreibe.
Zum Thema: ich würde Regelfanatiker immer nur zu gerne nochmal durch
einige Vorlesungen aus der Theoretischen Informatik scheuchen, nur
damit endlich mal der Groschen fällt.
Mit diesen Regeln wird keine neue Programmiersprache geschaffen, sie
können auch die charakteristischen Fehler gar nicht verhindern, dafür
sind sie aus mathematischer Sicht zu wenig modifizierend. Ich kann
also denselben Müll auch in MISRA völlig problemlos abliefern. Und
ich hatte in letzter Zeit einiges aus der Automobilbranche auf dem
Tisch und muss sagen, dass das auch gemacht wird. Die Leute sind sehr
kreativ, sie überschreiben auch nach wie vor mühelos rückwärts die
lokalen Variablen auf dem Stack, referenzieren mit großer Freude
Null-Pointer an selten betretenen Programmpfaden und verlieren sich
in Endlosschleifen. Und solche Fragmente werden nur zu gerne von
"Copy & Paste"-Entwicklern dann weiter verbreitet, weil es ja
"bisher" auch nicht geknallt hat. Davor kann MISRA nicht schützen.
Und natürlich auch nicht vor den besonders schönen Problemen mit
Threads und parallelen Programmabläufen.
Wenn man sagt, man hätte gerne eine Art "sinnvolles" Style-Guide, bei
dem manche Regeln höher gewichtet werden und andere nur Empfehlungen
sind, das kann ich nachvollziehen. Aber irgendeinen völlig
unwissenschaftlichen Blödsinn über solches Zeug zu behaupten, halte
ich auch in Anbetracht der Business- und Bullshitbingo-Apologeten,
die sich in der Softwareentwicklung breitmachen, für eine ganz, ganz
schlechte Idee und fachlich schlichtweg für Irreführung.
MFG/?
Wem Softwareentwicklung selber zu schwierig ist ...
? (mehr als 1000 Beiträge seit 02.06.03)
... der kann wenigstens noch andere schikanieren,
indem er für sie total sinnvolle Codier-Richtlinien
erfindet, wo alles, was er selber nicht kapiert hat,
unverständlich, gefährlich, unsicher und verboten ist.
?
Mein Name ist Programm.
Vermutlich ja. ;-)
Bei einigen Regeln habe ich leider auch den Eindruck, das man C auf
Kindergartenniveau downsizen will. Etwa wenn man bedingte Zuweisungen
generell verbietet. Gut, verschachtelt werden die etwas kryptisch,
aber sie helfen den Source-Code kompakt und lesbarer zu halten.
Re: Wem Softwareentwicklung selber zu schwierig ist ...
? (mehr als 1000 Beiträge seit 02.06.03)
? schrieb am 1. Mai 2013 12:26
> "Standards" wie MISRA kann man diese leider nur atomar betrachten. In
> kaum einem Unternehmen wird gesagt, lass uns mal ein bischen MISRA
> machen und nur das sinnvolle. Meist wird es heißen, absofort MISRA
> und dann wird mit einem Tool die Einhaltung überprüft. Dabei kommt
> der schlechteste MISRA konforme Code durch, aber sauberer nicht MISRA
> konformer Code muss kaputt gefixt werden.
Wenigstens Du hast das Grundprinzip von Codierrichtlinien
verstanden. Genau so läuft es nämlich bei jedem Großprojekt!
?
Mein Name ist Programm.
Reizthema Klammern
wa (mehr als 1000 Beiträge seit 13.01.00)
Christian Stieber schrieb am 30. April 2013 14:31
> Natürlich gibt es eine klare Reihenfolge was "a && b || c" bedeutet
Nun, ueber sowas meckert bereits der Compiler gern mal. Ist auch in
aller Regel allein schon wegen der Laenge solcher Ausdruecke schwer
lesbar. Ein paar hilfreiche Klammern, idealerweise gepaart mit
durchdachten Zeilenumbruechen, sind hier also nuetzlich.
> Auch bei Konstrukten wie "*p++" ist nicht sofort ersichtlich was
> passiert. "*(p++)" oder "(*p)++" machen das klar.
Da verwirrt mehr als es nuetzt. *p++ ist derart "normal", dass man
sich bei *(p++) erst mal wundert, was hier denn seltsames passiert,
dass die Klammern noetig sind. Ist "p" vielleicht ein Macro ? Usw.
Ein Uebermass an Klammern verschlechtert auch die Lesbarkeit des
Codes. So wird keinem geholfen: der Compiler haette es auch ohne die
Klammern verstanden, und der Programmierer muss sich darauf
konzentrieren, Klammern zu entflechten, statt den Sinn des Codes zu
erfassen.
Beispielsweise sollte man auch das Pascals verpfuschten Prioritaeten
zu verdankende Setzen von Klammern um relationale Ausdruecke
vermeiden. Also "a == b || a == c" statt "(a == b) || (a == c)". In
diesem einfachen Fall ist das zwar immernoch lesbar, aber man kommt
so recht schnell zu kryptischen Klammerwuesten.
- ?
Ist die Aufforderung ...
? (mehr als 1000 Beiträge seit 31.08.11)
.. die Operatorpräzedenz von C nicht als verbindlich anzusehen, immer
noch drin?
Also nicht vergessen:
c = a + b;
geht so nicht, denn der Compiler könnte es auch als
(c = a) + b;
interpretieren, wenn er sich nicht an die Operatorpräzedenz hält.
Also immer schön Klammern setzen, viele viele Klammern:
c = (a + b);
Re: Wunschdenken: intrinsisch sicheres C(++)
? ?, ? ? (mehr als 1000 Beiträge seit 10.01.00)
Compiler geben Dir bereits einen Haufen Warnungen, und man kann die
auch in Fehler "umschalten". Wenn man denn möchte...
Und genau daran hakelt es ja schon. Ich kämpfe regelmäßig mit z.B.
Boost, weil diese Sammlung von zusammengefrickeltem C++ Code bei
"scharfen" Einstellungen anfängt Warnings zu produzieren. Und bei mir
sind "scharfe" Einstellungen ebenso wie "-Werror" bzw. "/WX" der
Standard...
In anderen Fällen produziert "Open Source" Software beim Übersetzen
seitenweise Warnings, obwohl die Makefiles nichtmal "scharfe"
Warnings einschalten. Aber solange es keine Errors sind hält es halt
niemand für nötig sich darum zu kümmern.
Ich habe jetzt auch wenig Grund zu vermuten daß es bei "closed
Source" irgendwie besser aussieht. Da sieht man es halt nicht mehr.
Und wenn ich z.B. Code von "unseren" Indern sehe... da werden ständig
irgendwelche globalen Bools in obskurer Weise gesetzt und abgefragt,
da wird quer in der Gegend rumgesprungen was das Zeug hält, da werden
Implementierungen von Libraries angeschaut und das Zeug in gruselig
undokumentierter Weise verwendet, da werden Millionen obskure
Statusteilinformationen in der Gegend rumgeschoben, und bei
irgendwelchen Kombationen macht die "Save" Funktion dann schonmal
einen "Load" oder so. Oder Threads ohne Synchronisation. Oder oder
oder...
Entsprechend funktioniert das Zeug dann auch.
Sicherheit, Qualität und Zuverlässigkeit fangen im Kopf an. Ob Du den
Nagel gerade oder krumm reinschlägst hängt nur sehr gering vom
verwendeten Hammer ab.
? (mehr als 1000 Beiträge seit 20.11.12)
?.M schrieb am 3. Mai 2013 22:28
> > Wolltest du gerade sagen, dass der Linux Kernel
> > mit C++ sauberer wäre?
>
> Aber um Größenordnungen.
Nein. Eindeutig nein. Ich weiß nicht, im welchen Bereich du tätig
bist, aber wenn man selber in dem "low level" Bereich tätig ist, muss
man C++ fürcherlich finden.
Ich sage nicht, C++ ist allgemein fürchterlich, aber in dem low level
Bereich ist es eindeutig grausam. Und das aus vielen Gründen, die ich
hier nicht auflisten möchte. z.B. möchte ich keine virtuellen
Methodentabellen auf Kernel-Ebene haben. Ich möchte/muss den Speicher
vollständig überblicken können und kann mir keine unsichtbare
Tabellen erlauben. Darüberhinaus brauche ich sie überhaupt nicht.
Mach dich schlau, wie Klassen, Vererbung usw. im Speicher abgebildet
werden. Das, was da generiert wird gehört niemals im Kernel.
Ich würde dir empfehlen, dich schlau zu machen, wie der Punktoperator
überhaupt funktioniert. Also was alles konkret passiert, wenn du
objekt.function() aufrufst. Das, was da passiert gehört niemals in
einem Kernel, im Treibercode und allen (echtzeit) Systemen, die
völlig deterministisch arbeiten müssen.
Es gibt Fälle, wo sogar Funktionen zu viel sind und man schreibt
Makros stattdesen. Man kann sich da nicht mal einen Funcktionssprung
erlauben. Da mit Klassen und Methodentabellen zu kommen ist
Selbstmord und hört sich nach WINFler.
Klassen in Interrupt Handler... Gott im Himmel, mir wird schlecht.
Btw, es gab Experimente mit C++/Linux und die sind gescheitert. Die
Wartbarkeit ist nicht gestiegen, sondern gesunken.
> http://lwn.net/Articles/249460/
Wenn C++ toll in deinem Bereich ist, ok cool. Aber bitte nicht
behaupten, C++ sei überall toll.
> C++ bietet ne tolle Möglichkeiten große Projekte besser
> zu strukturieren.
Nein. Es sei denn, man hat wirklich keine Ahnung von C.
Der Kernel ist wunderbar strukturiert und das ohne C++.
> Richtiges OOP,
OOP ist ein Modell von vielen. Warum müsste ich unbedingt OOP machen?
Es geht wunderbar auch ohne. Ich selber war jahrelang mit Java
unterwegs. Ich sehe es aber nicht ein, dass OOP ein Ziel in sich sein
sollte.
Und zum Thema "richtiges": ich kann durch Pointerarithmetik auf dein
"private" Zeugs zugreiffen. Völlig mühelos.
Und was heißt richtig überhaupt? Warum soll Python-OOP schlecht sein?
> generische Programmierung,
Ich brauche sie überhaupt nicht. Auch mit Java habe ich sie nur
selten gebraucht. Und *wirklich* gebraucht habe ich sie nie.
> RAII, Exceptions.
Ich brauche sie nicht. Und im Treibercode möchte ich wirklich keine
Exceptions sehen. Aus verschiedenen Gründen.
> Nur haben Leute die Betriebssysteme eine Lowlevel-Denke
> die sich nicht mit Abstraktion (die im Falle von C++ kaum
> Performance kostet) nicht vereinbart.
Hä? Ich sehe in dem Linux-Treibermodell viel mehr Abstraktion als in
vielen C++/Java Projekten. Kann es sein, dass du einfach keine
Erfahrung auf dem Gebiet hast und nur so allgemein von C++ ist cool
redest? Sag einfach so, dass du nur C++ kennst und dass du es toll
findest. Cool.
Ich bin mal den MISRA-C-Standard durch und habe fast für JEDE Regel
eine Ausnahme gefunden.
Ich sehe es genauso wie Du. Es ist ein guter Hinweis, solche Regeln
zu kennen und vor allem die Motivation, die die Leute damit haben.
Ich habe nur eine Regel: fass Dich kurz, aber nutze
alle Möglichkeiten von C, damit Code sauber ist
(möglichst strenge und exakte Typen, drastische Scope-Eingrenzungen etc.).
Allerdings kann man diese Regel nur durchsetzen, wenn man
genügend Erfahrung hat.
Ich bin sogar dagegen goto zu verbieten.
Ich habe genau EIN Beispiel für gute Praxis damit gefunden
und dazu von renomierten C-Hackern und da darf man von denen lernen.
Das Problem mit MISRA habe ich insofern, als dass ich (laut Kundenfeedback)
ein sehr guter Programmierer bin, der eben auch von sich aus leserlichen
Code schreibt.
Ich würde durch MISRA definitiv massiv ausgebremst und der Code würde
unleserlicher mit, als nach meinen eigenen Regeln.
MISRA ist die Anwort von Managern auf die Frage, wie programmier-unerfahrene
Ingenieure fehlerarmen C-Code schreiben können.
Das Dilemma: es geht nicht!
Leider begreifen die Verantwortlichen das einfach nicht, oder nutzen
den Microsoft-Effekt aus: wenn der PC muckt unter Windows, kann man die Schuld
auf Microsoft abladen und man selbst ist fein raus;
wenn man dagegen Linux nutzt, ist man selber Schuld, wenn es mal Probleme gibt.
Genau _so_ "verkauft" sich MISRA.
Letztlich können nur gute _embedded_ Programmierer guten Code schreiben.
Die brauchen dann aber auch kein MISRA, sondern gescheite Style Guides.
Damit kann man auch einige extrem nützliche Extensions moderner Compiler
wie GCC erlauben, die gerade auch zur Qualtität des Codes massiv beitragen
können (Stichworte "gcc plan9-extensions").
MISRA stammt immerhin aus einer Zeit, als die meisten embedded Compiler
noch K&R-C implementierten und moderne Programmiertechniken (also der 70er Jahre!)
den Auto-Ingenieuren völlig unbekannt waren.
Das gilt leider auch für die Leute, die MISRA erst definiert hatten.
Inwieweit das mit MISRA-2012 anders ist, kann man leider aufgrund
der Paywall nicht so einfach feststellen.
Ich auch ned, wundere mich aber dauernd über die - trotz MISRA - häufingen
Liegenbleiber und Rückrufe wegen Softwarefehlern in Steuergeräten.
Und das ausgerechnet in den "Premium" Mühlen.
Wie gesagt: erfahrene SW-Entwickler brauchen MISRA bestenfalls anfangs als Liste
möglicher Pitfalls (dafür ist es tatsächlich ok, wenn auch (MISRA-2004) massiv unvollständig).
Und schlechte Progger werden mit MISRA nicht wirklich guten Code schreiben.
Wie gesagt, ich bin extrem froh, nicht MISRA nutzen zu können.
Das erlaubt mir eben die plan9-extensions nutzen zu können, also
OOP in C ohne overhead, etc. und das typsicher (Compiletime)
ohne die cast-Krankheit. Ebenso das union-Verbot von MISRA.
Fakt ist, dass MISRA mit seinen Regeln schlicht die Möglichkeiten
moderner Compiler verhindert (daher sind die commerziellen
embedded-Compiler ja oftmals auch derartige Krücken) und
moderne Programmiertechniken unterbindet.
Obwohl beides masiv zur Qualität beitragen könnte.
Dafür sieht man immer noch, dass z.B. Variablen zwischen Threads
(bzw. interrupt handler und normalen code) nicht als volatile
deklariert sind.
Ja, das mag auch IAR&Co laufen, weil die Teile eben
mit solchen Deppen rechnen, aber es behindert die Optimierung
gescheiter Compiler.
Das Allerwelts-Heilmittel der Manager Unit-/Integration-/etc.-Test
wirds ja schon finden...
Der beste Test ist der, den man nicht schreiben muss, weil
der Testcase gar nicht auftreten kann.
Übrigens habe ich sowas oft auch so implementiert gesehen:
int ok = 1;
i = 10;
while ( ok ) {
...
i--;
if ( i == o) ok = 0;
}
MISRA konform, aber völlig unübersichtlich.
>> Also auch kein Flag in der Schleifenbedingung, das man
>> unterwegs auf 'fertig' setzt?
> Warum?
> done = FALSE;
> for(ii = 10; ii > 0; --ii) {
> if(done == FALSE)
> {
> ...
> if(...)
> { done = TRUE; }
> }
> }
> So vermeidet man, die Schleife abbrechen zu müssen - man führt
> alle Durchläufe durch, macht aber eventuell nichts.
Dein "eventuell" deutet ja schon darauf hin: solcher Art Programmierung
ist nur mehr dazu da, irgendwelche hahnebüchenen Standards zu erfüllen, rückt
aber von klarer Logik bzw. Verständlichkeit weit ab.
Denn, wenn das "done"-if irgendwelchen Nachbarcode bekommt, dann ist die Schleife
doch nicht so ganz done, und wenn es keinen bekommt, dann verliert es seine
Existenzberechtigung, denn einen Schleifenzähler leer raufzählen lassen
ist verwirrend, weil es andeutet, dass dadurch eine Invariante erfüllt wird
oder, ganz schlimm, im for() irgendwelche side effects ausgelöst werden.
Safe code wird nicht durch das Ignorieren von POLS erreicht, sondern
durch ein besseres Abstraktionsniveau.
Also wenn schon, dann ganz weg mit der C for-Schleife und was klares, eingeschränktes
verwenden für solche Programmteile, aber nicht irgendwelchen style Unfug, der
nur durch Reviews halbwegs validierbar ist.
>> ...und noch dazu sehr dürftig.
>> Der Artikel ist nur für Leute geschrieben, die MISRA sowieso schon kennen.
>> Schade.
> Oder für Manager, die C sowieso nicht kennen, mit
> Beispielen also nichts anfangen könnten.
Bingo. MISRA wird vor allem in diesen Etagen als Buzzword verwendet, das die
Hoffnung befoerdert, "irgendwie" bessere Software hervorzubringen als ohne MISRA.
Das ist der wahre Verdienst des Konsortiums: MISRA als selling point.
Was dahinter steckt, kuemmert nicht.
Ein klein wenig wie ein angebissener Apfel... :D
Eher wuerde ich sagen: ohne Rekursion und goto bekommt man eine
Motorsteuerung hin, nicht aber ohne Pointer.
Das Arbeiten mit physikalischen Systemen bedingt fast immer auch
die Benutzung von verschiedensten (multidimensionalen) Tabellen, die
ohne Filesystem in wunderlich segmentierten Flashbereichen liegen, und
wer C halbwegs kennt, weiss, wie sehr dieses "kein Pointer"-Paradigma
in so einem Fall zum Selbstbetrug, zur Verkomplizierung und
moeglicherweise sogar zur Performance-Bremse wird.
> Kann man nachvolliehen.
Nicht wirklich. a[i] syntaktischer Zucker für *(a + i).
Man benutzt also in jedem nichttrivialen C-Programm Zeigerarithmetik, auch
wenn man das vielleicht nicht auf den ersten Blick sieht.
Und ich weiß auch nicht, wem dadurch geholfen werden soll, dass man
&a[i] statt a+i schreiben muss.
Naja, außer Leuten, die die o. g. Beziehung zwischen [] und *(+)
nicht verstehen, aber die sollten sowieso nicht
in die Nähe eines Compilers gelassen werden.
>> a[i] syntaktischer Zucker für *(a + i).
>> [...] wem dadurch geholfen werden soll, dass man
>> &a[i] statt a+i schreiben muss.
> Und weil + kommutativ ist, kann man auch gleich i[a] schreiben.
> Ich finde es sehr gut, wenn man sich da auf _eine_ sinnvolle Schreibweise festlegt.
Die sinnvolle Schreibweise ist a + i und nicht &a[i].
Letzteres ist syntaktischer Zucker für &*(a+i), und das ist
offensichtlich Unfug.
Es kommt doch auch niemand auf die Idee, &*a statt a zu schreiben.
>> Naja, außer Leuten, die die o. g. Beziehung zwischen [] und *(+)
>> nicht verstehen, aber die sollten sowieso nicht in die Nähe
>> eines Compilers gelassen werden.
> Ist das noch Arroganz oder schon Überheblichkeit?
Ist es auch arrogant, wenn man die Meinung vertritt, dass sich
jemand, der Gas- und Bremspedal nicht auseinander halten kann, aus
dem öffentlichen Straßeverkehr heraushält?
--
Ich würde sagen weder noch. Wer seine Sprache nicht beherrscht, sollte tatsächlich
nicht an kritische Projekte herangelassen werden - MISRA hin oder her.
MISRA wurde von der Automotive-Industrie in der Rueckschau entworfen,
als klar wurde, dass mit der Sprache C nicht mal "eben so" programmiert
werden konnte, weil selbst informatisch ausgebildete Nicht-C-Programmierer
(und die am Beginn weit verbreiteten umgeschulten Elektrotechnik und
Maschinenbau-Ingenieure sowieso) ueber die Unzulaenglichkeiten der Sprache
stolpern.
Polemisch gesagt, aus Nicht-C-Programmierern werden miserable C-Programmierer,
daher der Name.
Warum sich gerade die (deutsche) Automobilindustrie so bereitwillig
in die Geiselhaft der Sprache C begeben hat, ist mir noch heute schleierhaft,
denn die Tools (Compiler) fuer den Loewenanteil der Steuergeraete
waren noch bis weit nach 2000 vollkommen hahnebuechen, teilweise sogar
von C89 abweichend (erinnert sich noch jemand an den Cosmic-Praeprozessor?)
und bei der Handvoll an automotive-grade CPUs haette die Finanzierung
z.B. einer Modula-2 Toolchain im Nachhinein gigantische Kosten gespart.
So stehen wir nun noch immer mit C da, C89 ist durch Autosar fuer weitere Jahre
als Standard einzementiert, es gibt Heerscharen an Beinahe-Programmierern, die
zwar MISRA befolgen, aber die zugrunde liegenden Probleme
(wie C die abstrakte Maschine auf ihre reale Plattform abbildet)
nicht annaehernd verstehen, und ein Haufen Manager, die sich
mangels Fachkenntnis an leicht zu merkenden Begriffen wie MISRA
und Autosar festhalten.
Fazit: fuer jemanden der C beherrschen will, sollte die Religion
"LINT" und nicht MISRA sein.
Der_Irre_Polterer (mehr als 1000 Beiträge seit 23.02.04)
Diethilde schrieb am 20. September 2013 23:26
> if ((read_c0_prid() & 0xff) >= 0x0050)
> return read_c0_count();
> break;
>
> Wenn ich sowas sehe kriege ich Wutanfälle.
Ohne Grund
> return mitten drin.
Ist sogar guter Stil. "One return" war ein Irrweg aus den 60ern.
Geboren aus Gedanken an Prozesoren ohne Pipelines und on-Chip-Caches
> Literale statt Symbole.
In diesem Fall tatsächlich übersichtlicher.
> Funktionsaufruf als Operand.
Yep. Guter Stil: Retun value optimization
Re: Denkt denn keiner an die Übersicht!
Roland Weber, Roland Weber (mehr als 1000 Beiträge seit 05.07.02)
bazzo schrieb am 21. September 2013 20:53
> Ein einziger Ausgang aus einer Funktion ist und bleibt einfach
> übersichtlicher!
Das kommt ganz darauf an, wieviel Code zwischen der Stelle, wo der
Rückgabewert feststeht und der Stelle, wo das "return" steht, noch
übersprungen werden muß.
Ich persönlich frage meistens ganz am Anfang einer Methode ein paar
Sonderfälle ab, die zum Beispiel zu einem null-Rückgabewert oder
einem bestimmten Boolean-Ergebnis führen. Dann schreibe ich das
return auch genau da vorne hin.
Das finde ich sehr viel übersichtlicher, als
praktisch den gesamten Methodenrumpf in ein if zu kapseln und weiter
einzurücken, nur damit am Ende ein einziges return stehen kann.
ciao,
Roland
Re: Denkt denn keiner an die Übersicht!
Diethilde (mehr als 1000 Beiträge seit 20.11.12)
Völlig verständlich und auch gängig.
Es ist natürlich übersichtlicher, wenn man schreibt
if (data == NULL) return ERROR_DATA;
if (buffer == NULL) return ERROR_BUFFER;
read(data, buffer);
als
if (data != NULL)
{
if (buffer != NULL)
{
read(data, buffer);
...
}
else
{
return_val = ERROR_BUFFER;
}
}
else
{
return_val = ERROR_DATA;
}
return return_val;
Manchmal aber geht es um die Einhaltung von Coding Styles, die keine
Abweichungen erlauben und die u.U. nerven.
Re: if ((read_c0_prid() & 0xff) >= 0x0050)
Pickwick81 (mehr als 1000 Beiträge seit 12.07.02)
Diethilde schrieb am 22. September 2013 00:14
> Nein. Grund ist: für komplizierte Dinge ist es hilfreich, davon
> ausgehen zu können, dass es nur ein return gibt.
Für komplizierte Dinge ist es hilfreich, genau das zu tun, was man
zum jeweiligen Zeitpunkt weiß, weil das Codezeilen spart und
Komplexität verringert. Wenn man weiß, dass man fertig ist, beendet
man also. Ganz simpel eigentlich.
> Nop, Return value optimization ist eine Compiler-optimierung, nicht
> eine Sache die du machen solltest:
Trotzdem kann man solche Dinge wissen und dem Compiler helfen und im
konkreten Fall kann man sich eine extra Variable im umgebenden
Gültigkeitsbereich nun mal sparen.
Re: if ((read_c0_prid() & 0xff) >= 0x0050)
Amoebus (8 Beiträge seit 23.12.12)
> return mitten drin.
Das unbedingte "Return am Ende" liegt vernünftigerweise schon
ziemlich lange auf dem Müllhaufen der Programmier(-Stil)-Geschichte.
Re: if ((read_c0_prid() & 0xff) >= 0x0050)
George99 (mehr als 1000 Beiträge seit 10.10.05)
Diethilde schrieb am 21. September 2013 22:59
> Sagt dir MISRA-C etwas?
Ich habe mir mal
> http://portal.automotive-his.de/images/pdf/SoftwareTest/his_subset_misra_c_1.0.3.pdf
angesehen, welches im Wiki-Artikel verlinkt ist. Größtenteils stehen
da (banale) Selbstverständlichkeiten, tw. Anforderungen, die wohl dem
begrenzten Speicher im Embedded-Bereich geschuldet sind und auch nur
dort sinnvoll sind (keine Rekursion benutzen, best.
library-Funktionen nicht benutzen) tw. völlig Unsinniges (kein break,
goto, continue, keine Pointer-Arithmetik benutzen, auch wenn sie
sinnvoll wären)
Das, was von den Regeln sinnvoll ist, weiß sowieso jeder
C-Programmierer, welche zusätzlichen Einschränkungen im
Embedded-Bereich zu berücksichtigen sind, sollte auch ohne
Regelsammlung klar sein und tw. ist es eben auch sinnlos.
Aus anderen Foren
Meine Erfahrungen mit MISRA sehen so aus:
In den frühen 90ern habe ich mal eine Bastelei abgeliefert, die im Wesentlichen
als Protokollumsetzer gearbeitet hat, das waren ein paar Zeilen Assembler
und weil's eine Insellösung war, hat sich niemand drum geschert.
Später wurde das Ding um einen weiteren Bus aufgestockt und ich hab's
mit einem Pascal neu gemacht, hat auch niemanden gejuckt.
Letztes Jahr mußte die Sache aus technischen Gründen nochmal erweitert
komplett neu designt werden, also in C, weil ein zugekaufter Netzwerkstack
integriert werden sollte.
Bei der Abnahme sagte man mir alles schön und gut, aber ist es auch MISRA- konform?
War mir völlig entgangen, aber Hausregel ist: Wenn C, dann nur MISRA.
Hätte ich Pascal genommen, wärs ihnen wurscht gewesen, dann hätte ich aber
den Stack selbst schreiben müssen.
Natürlich war's nicht konform. Nach dem Reformat- Lauf kommen einem manchmal
auch eigene Module seltsam vor, weil man's optisch einfach anders im Gedächtnis hat.
Natürlich wurden auch etliche Konstrukte bemängelt, die aber einwandfrei funktioniert haben.
Eine Totalkatastrophe war dann auch noch die zugekaufte Lib, wenn fremder Code
MISRA- konform gemacht werden muß, muß man das ganze benörgelte Zeug auch verstehen.
Also der Umbau hat fast nochmal soviel Zeit gekostet wie das erste Design,
ohne daß das in irgendeiner Weise produktiv war oder bezahlt wurde.
Deswegen bin ich erstmal sauer auf das Beharren auf MISRA.
Ich bin seit 16 Jahren der Einzige, der an das Projekt hinpfuscht
und wage zu behaupten, daß die Anlage durch MISRA weder wartbarer geworden ist
noch an Stabilität gewonnen hat, an einigen Stellen sogar deutlich umständlicher.
Die Frage müßte lauten, ob es hier jemanden gibt, der sagt, fremden Code
kapier' ich viel schneller, wenn er MISRA- konform geschrieben ist,
dann hätte es einen Nutzen.
Ans Eingemachte geht es aber, wenn man mit Funktionspointern herumhantiert.
Ich habe so eine verkettete Eventhandlerliste implementiert, da wird alles
als void* draufgeschoben, die aufzurufenden Funktionen (alle void(void))
und auch die Parameter als (void *) einer struct irgendwas.
Jede aufgerufene Funktion holt sich aus der Liste den Pointer auf die Argumente
und muß halt mit einem free() das Argumentepaket nach der Abarbeitung löschen,
also eigentlich durchschaubar, aber nach MISRA stockverboten.
Als Umgehungskonstrukt ist mir nur eingefallen, Event- IDs in eine Liste
zu schieben und die über eine lange switch/case zu parsen.
Vorher war's sowohl übersichtlicher als auch performanter.
Glaube nicht, daß jemand nach der MISRA-Adaption sagen könnte:
"Das kapier' ich schneller".