mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Probleme mit MISRA C


Autor: Mr Bean (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
http://ftp.iar.se/WWWfiles/guides/MisraC.pdf

Steht alles mit Beispielen drin.

Gruss:

Dennis

Autor: Mr Bean (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Erich (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: 123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
x = maxErrorcount << 8;
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.

Autor: Mr Bean (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: 123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Malzeit

ggf könnte auch klammern helfen. einen versuch währe es wert.
maxErrorcount = (maxErrorcount << 8);

Wenn der Compiler fehlerhaft implementiert währe. Dann könnte die zeile
maxErrorcount = maxErrorcount << 8;

ja in
maxErrorcount = maxErrorcount;
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.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gibt das hier auch eine MISRA-Fehlermeldung?
  maxerrorcount <<= 8;

Autor: Erich (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: 123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Mr Bean (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Jap, habe die Syntax
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mr Bean schrieb:
> Allerdings hab ich den Tasking Compiler

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

Autor: Mr Bean (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Hennig (stefanhennig)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Norbert (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Norbert (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <stdio.h>
#define A 0x12345678

void sub1(int n) {
  printf("%#x << %d = %#x\n", A, n, A << n);
}

void sub2(int n) {
  n = 36; // ändert nichts am Inhalt von n
  printf("%#x << %d = %#x\n", A, n, A << n);
}
static
void sub3(int n) {
  printf("%#x << %d = %#x\n", A, n, A << n);
}

int main(void) {
  sub1(36); sub2(36); sub3(36);
  return 0;
}

Ausgabe:
0x12345678 << 36 = 0x23456780
0x12345678 << 36 = 0
0x12345678 << 36 = 0

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

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Klaus Wachtler (mfgkw)
Datum:

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

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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 ;-)

Autor: abc (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.