Forum: Mikrocontroller und Digitale Elektronik Probleme mit MISRA C


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Mr Bean (Gast)


Lesenswert?

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

von Dennis (Gast)


Lesenswert?

http://ftp.iar.se/WWWfiles/guides/MisraC.pdf

Steht alles mit Beispielen drin.

Gruss:

Dennis

von Mr Bean (Gast)


Lesenswert?

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

von Erich (Gast)


Lesenswert?

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

von 123 (Gast)


Lesenswert?

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.

von Mr Bean (Gast)


Lesenswert?

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

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von 123 (Gast)


Lesenswert?

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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Gibt das hier auch eine MISRA-Fehlermeldung?
1
  maxerrorcount <<= 8;

von Erich (Gast)


Lesenswert?

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

von 123 (Gast)


Lesenswert?

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.

von Mr Bean (Gast)


Lesenswert?

Hallo

Jap, habe die Syntax
1
maxErrorcount <<= 8;
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

von Karl H. (kbuchegg)


Lesenswert?

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?

von Mark B. (markbrandis)


Lesenswert?

Mr Bean schrieb:
> Allerdings hab ich den Tasking Compiler

Oh je - vielleicht noch gar für einen ST10 Mikrocontroller? ;-)

von Mr Bean (Gast)


Lesenswert?

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

von Stefan H. (stefanhennig)


Lesenswert?

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

von Oliver (Gast)


Lesenswert?

Mr Bean schrieb:
> Was wäre bei einer 8bit Variablen zu beachten (im
> Zusammenhang mit MISRA-C)?

Das "<<8" darauf schon etwas fragwürdig wäre.

Oliver

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Norbert (Gast)


Lesenswert?

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?

von Klaus W. (mfgkw)


Lesenswert?

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.

von Norbert (Gast)


Lesenswert?

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!

von Yalu X. (yalu) (Moderator)


Lesenswert?

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:
1
#include <stdio.h>
2
#define A 0x12345678
3
4
void sub1(int n) {
5
  printf("%#x << %d = %#x\n", A, n, A << n);
6
}
7
8
void sub2(int n) {
9
  n = 36; // ändert nichts am Inhalt von n
10
  printf("%#x << %d = %#x\n", A, n, A << n);
11
}
12
static
13
void sub3(int n) {
14
  printf("%#x << %d = %#x\n", A, n, A << n);
15
}
16
17
int main(void) {
18
  sub1(36); sub2(36); sub3(36);
19
  return 0;
20
}

Ausgabe:
1
0x12345678 << 36 = 0x23456780
2
0x12345678 << 36 = 0
3
0x12345678 << 36 = 0

Compiler ist der GCC für x86 mit -O2.

von Klaus W. (mfgkw)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Klaus W. (mfgkw)


Lesenswert?

Angeber!
Ich habe erst 4.3.2, da muß ich wohl mal nachrüsten! :-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

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 ;-)

von abc (Gast)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.