Probleme mit MISRA C

Gast #1939919
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
Gast #1939952
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
Gast #1939962
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
Gast #1939968
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.
Gast #1940029
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
Moderator #1940088
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.
Gast #1940252
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.
Gast #1940447
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.
Gast #1940593
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
Gast #1942000
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
#1942010
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
Moderator #1942783
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.
Gast #1942902
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?
#1942916
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.
Moderator #1943220
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.
Moderator #1943625
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.
Gast #1943644
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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren