Hallo
Ich muss bei meiner Software den MISRA-C Standard einhalten. Leider ist
die Erklärung der Regeln nicht wirklich umfangreich.
z.B. bekomme ich bei der Zeile:
maxErrorcount = maxErrorcount << 8;
Die MISRA-C Fehlermeldung:
"line 69: MISRA C rule 53 violation: [R] all non-null statements shall
have a side-effect"
Was ist damit gemeint? bzw. Wie kann ich diese Regel erfüllen?
Habt ihr mir vielleicht eine gute Dokumentation, in der die Regeln
beschrieben sind?
Würde mir wahrscheinlich auch sehr weiterhelfen. Im Moment bin ich bei
153 MISRA-C violations...
Hab also noch etwas vor mir.
Grüße
Bean
Hallo
Vielen Dank für die Antwort.
Hab mir mal ein paar Regeln die bei mir verletzt werden in dem Dokument
durchgelesen.
Zu Regel 53 (obiges Beispiel):
Heist das jetzt für mich dass ich die Variable maxErrorcount als
volatile deklarieren muss?
Hier mal die Erklärung zu der Regel:
"The compiler will generate an error, indicating a violation of this
rule, if a statement
does not contain a function call, an assignment, an operator with a
side-effect (++ and
--), or an access to a volatile variable."
Regel 53 wird bei mir sehr oft verletzt. Meistens eben bei einfachen
Variablen Operationen (schieben). Es kann ja auch keine Lösung sein
einfach jede Variable als Volatile zu deklarieren.
Grüße
Bean
Die MISRA rules unterscheiden zwischen
(required)
(advisory)
Zunächst konzentriert man sich auf die required rules.
Regel 53 ist allerdings eine (required).
An deiner Programmzeile
>maxErrorcount = maxErrorcount << 8;
fällt auf, daß dieselbe Variable als Quelle und Ziel eingesetzt wird.
Das ist prinzipiell schlecht.
Folgen gar mehrere solche Zuweisungen auf maxErrorcount hintereinandern,
so ist das Programm auch im Debugger schwierig verfolgbar, denn es kann
keine Berechnungsschritt einzeln wiederholt werden.
Entweder
= einzelne Zwischenvariablen verwenden (die auch Autovariablen sein
können, daß optimiert der Compiler dann schon)
= oder mehrere solche aufeinanderfolgenden Zeilen zusammenfassen
(einsetzen) und korrekt klammern
= oder tatsächliche die Variable als volatile deklarieren
ich könnte da mehrere probleme erkennen.
weil links und rechts die gleiche variable verwendet wird. versuch mal
eine temp variable einzuführen, und die danach zuweisen.
1
x=maxErrorcount<<8;
2
maxErrorcount=x;
Misra muss einem nicht immer auf dem ersten blick logisch sein. vieles
davon sollte ein standard konformer compiler auch nicht fehlerhaft
machen. nur die Automobil industrie ist da früher des öfteren böse in
die falle getapt.
Hallo
Also die Lösung mit einer zusätzlichen Variable funktioniert. Allerdings
Finde ich es eher unübersichtlich für jede kleine Operation über ein
"help" Variable zu gehen. Das macht den Code denke ich eher
komplizierter zu lesen. Naja, da muss ich dann wohl durch...
Bin mal gespannt welche Lösungen ich für die ganzen anderen Regeln
finde...
Grüße
Bean
Normalerweise hat die Programmzeile einen Seiteneffekt, da es sich um
eine Zuweisung handelt. Es könnte höchstens sein, dass der Compiler
erkennt, dass maxErrorcount an dieser Stelle immer 0 ist. Dann wäre die
Anweisung tatsächlich überflüssig und die Meldung nachvollziehbar.
Malzeit
ggf könnte auch klammern helfen. einen versuch währe es wert.
1
maxErrorcount=(maxErrorcount<<8);
Wenn der Compiler fehlerhaft implementiert währe. Dann könnte die zeile
1
maxErrorcount=maxErrorcount<<8;
ja in
1
maxErrorcount=maxErrorcount;
2
maxErrorcount<<8;
zerlegt werden. was nach standard zwar falsch währe, aber ggf auftreten
könnte. Sei es auf grund von optimierungen, ...
Ein Seiteneffekt ist durch die verwendung der Variable maxErrorcount
auf der Linken und rechten seite gegeben.
Habe die verschiedene Syntax mit meinem MISRA tool jetzt kurz geprüft.
Hierbei tritt kein Fehler auf.
Aber wie schon beschrieben ist die Zuweisung auf dieselbe Variable nicht
toll, und so mögen verschiedene MISRA tools das ggf. unterschiedlich
bewerten.
Ich verwende DAC von Ristancase.
http://www.ristancase.com/index.html
Kleine Korrektur:
nicht die MISRA Tools mögen das nicht, MISRA mag das nicht, die tools
folgen nur den regel die MISRA aufgesetzt hat.
ggf kann man auch, wenn man weis was man da macht, und es erlaubt ist,
vorausgesetzt, in bestimmten bereichen die regel von MISRA deaktivieren.
gerade mit meinem Tool (Tasking) getestet. Die Fehlermeldung bleibt
bestehen.
Die IDE von Ristancase sieht auch nicht schlecht aus. Allerdings hab ich
den Tasking Compiler inklusive MISRA-C support schon.
Aber trotzdem vielen Dank!
Grüße
Bean
Mr Bean schrieb:
Das das noch keiner gefragt hat.
Welchen Datentyp hat denn maxErrorcount?
Kenn es sein, dass es sich dabei zufällig um einen 8 Bit Datentyp
handelt?
Hallo
Nein, bei maxErrorcount handelt es sich um ein uint16_t. Also um eine
16bit Variable. Was wäre bei einer 8bit Variablen zu beachten (im
Zusammenhang mit MISRA-C)?
Controller ist ein SiLabs. Ist der Compiler schlecht? Oder warum das oh
jeh!? Ich bin bis jetzt eigentlich ganz gut mit dem Compiler zurecht
gekommen. Nur MISRA-C macht mir das Leben etwas schwer...
Grüße
Bean
Mr Bean schrieb:> Hallo>> Nein, bei maxErrorcount handelt es sich um ein uint16_t. Also um eine> 16bit Variable. Was wäre bei einer 8bit Variablen zu beachten (im> Zusammenhang mit MISRA-C)?>
Ich lass mich da gern korrigieren, aber shift-Operationen mit mehr oder
gleich viel Schritten wie der Typ breit ist können (?) NOOPs sein.
Ich war mal sehr erstaunt, als ein u32XYZ<<32u statt 0 den unveränderten
Wert ergeben hat. Noch erstaunter war ich, als ich nachgelesen hatte,
dass das i.O. ist.
Grüße,
Stefan
Karl heinz Buchegger schrieb:> Kenn es sein, dass es sich dabei zufällig um einen 8 Bit Datentyp> handelt?
Aber auch bei 8 Bit hat die Anweisung einen Seiteneffekt, nämlich den,
die Variable mit dem Wert 0 zu überschreiben.
Stefan Hennig schrieb:> Ich lass mich da gern korrigieren, aber shift-Operationen mit mehr oder> gleich viel Schritten wie der Typ breit ist können (?) NOOPs sein.
Das ist nur dann der Fall, wenn der rechte Operand größer oder gleich
der Breite des promoteten Typs des linken Operands ist. Da in diesem
Fall nach int promotet wird und int bei einem standardkonformen Compiler
immer breiter als 8 Bit ist, ist die Operation schon in Ordnung, auch
wenn sie natürlich nicht allzuviel Sinn ergibt, da man genausogut
maxErrorcount=0 schreiben könnte.
Stefan Hennig schrieb:> Ich war mal sehr erstaunt, als ein u32XYZ<<32u statt 0 den unveränderten> Wert ergeben hat. Noch erstaunter war ich, als ich nachgelesen hatte,> dass das i.O. ist.
Ich bin erstaunt das man dieses Resultat irgendwo 'für gut befunden'
nachlesen kann. (Bei 32 mal ROL in Assembler kann ich das ja verstehen,
aber bei Shift Operationen...)
Gab's für diese doch einigermassen erstaunliche Aussage auch eine
Begründung?
Bspw. ISO/IEC 9899:201x sagt dazu folgendes:
> 6.5.7 Bitwise shift operators> ...>> Semantics>> The integer promotions are performed on each of the operands.> The type of the result is that of the promoted left operand.> If the value of the right operand is negative or is greater> than or equal to the width of the promoted left operand, the> behavior is undefined.> ...
Damit steht es einem Compiler frei, bei einem Shift um 32 Bit
einfach mal nichts zu machen.
Klaus Wachtler schrieb:> Damit steht es einem Compiler frei, bei einem Shift um 32 Bit> einfach mal nichts zu machen.
Vielen Dank für die Info, wieder etwas gelernt!
Dass das Ergebnis von Shift-Operationen mit zu großen Shift-Weiten
wirklich "undefined" und nicht nur "implementation defined" ist, zeigt
das folgende Beispiel, wo die Operation trotz gleicher Operanden je nach
Kontext unterschiedliche Ergebnisse liefert:
Witzigerweise bekomme ich bei mir mit -O1 genau diese Ausgabe,
mit -O2 -und -O3 dagegen lauter Nullen.
Spricht aber nicht gegen deine Aussage, sondern erst recht dafür.
Klaus Wachtler schrieb:> Witzigerweise bekomme ich bei mir mit -O1 genau diese Ausgabe,> mit -O2 -und -O3 dagegen lauter Nullen.
Das passiert bei mir erst bei -O3. Dann werden alle drei Funktionen
geinlinet, bei -O2, -O1 und -Os nur die static-Funktion und bei -O0
überhaupt keine. Nur bei static- und/oder geinlineten Funktionen oder
der expliziten Zuweisung n=36 am Anfang von sub2 kann der Compiler den
Wert von n vorhersehen und deswegen den Ausdruck schon zur Compilezeit
berechnen, was in diesem Fall (erlaubterweise) ein anderes Ergebnis als
zur Laufzeit liefert. Der Compiler liefert erwartungsgemäß 0, der SALL-
Befehl des Prozessors hingegen betrachtet vom rechten Operanden nur die
letzten 5 Bits, was zum Ergebnis A<<(36&0x1f) = A<<4 führt.
Da kann es natürlich je nach Compilerversion Unterschiede geben, ich
habe GCC 4.5.1.
Klaus Wachtler schrieb:> Ich habe erst 4.3.2, da muß ich wohl mal nachrüsten! :-)
Wieso, ist doch ok. Wenn dein Compiler schon mit -O2 so gut optimiert
wie meiner mit -O3, dann hast du offensichtlich die bessere Wahl
getroffen ;-)
Bei sub2 wird n inerhalb der funktion überschrieben. egal ob gleicher
wert oder nicht. der wert ist somit beim schieben bekannt, und kann
daher zur compile ziet definiert werden.
Bei sub3 greift so was ähnliches wie bei sub2. sub3 darf (wenn ich mich
jetzt nicht toatl vertu) nur inerhalb der definierten datei verwendet
werden. dadurch weiss der compeiler alle aufrufe und deren parameter.
ensprechend ergeben sich dadurch auch optimierungsmöglichkeiten, bis hin
zur ersetzung durch einen fixen wert.
zu sub1. hier kann der compiler eigentlich gar nicht optimieren, die
Funktion kann auch von aussen aufgerufen werden. nur inerhalb der
überzetzungseinheit kann er entsprechend optimieren. so wie bei sub2
oder sub3.
Hier ist es dann architektur abhängig, was bei einem shift grösser 32
passiert. 80x86 kann sich anders verhalten als ARMv5 oder 8051 oder
PowerPC, ...
schlussfolgerung. würde mann die sub1 Funktion in eine eigene datei
auslagern, und einzeln übersetzen, müsste egal bei welcher optimierung
das gleiche verhalten ersichtlich sein.
auser der compiler optimiert den code nach dem linken noch einmal.
gruss