Forum: Compiler & IDEs Erklärung für Macrodefinition wird benötigt


von Michael S. (michael8192)


Lesenswert?

Hallo zusammen

Kann mir bitte jemand erklären, wie dieses Macro zu verstehen ist, also 
was da genau gemacht wird? Und wieso nach dem ersten asm(); ein 
Semikolon hinkommt und nach dem zweiten nicht? Das Macro ist aus PIC18.h 
und wird dazu benötigt, um EEPROM Speicherzellen bei der Programmierung 
zu initialisieren.
Hintergrund: Ich bekomme eine MISRA-Regelverletzung und weiss nicht wo 
und wie ich da Klammern einfügen soll.
[ MISRA 19.10 ] In the definition of a function-like macro each instance 
of a parameter shall be enclosed in parentheses unless it is used as the 
operand of # or ##.
Vielen Dank
1
#define __EEPROM_DATA(a, b, c, d, e, f, g, h) \
2
                         asm("\tpsect eeprom_data,class=EEDATA,delta=2,space=2"); \
3
                         asm("\tdb\t" ___mkstr(a) "," ___mkstr(b) "," ___mkstr(c) "," ___mkstr(d) "," \
4
                                      ___mkstr(e) "," ___mkstr(f) "," ___mkstr(g) "," ___mkstr(h))

von Uwe (de0508)


Lesenswert?

Hallo,

ein Tipp, was passiert bei ?
1
__EEPROM_DATA(a, b, c, d, e, f, g, h);

Und wie wäre es das Macro etwas abzuändern:
1
#define __EEPROM_DATA(a, b, c, d, e, f, g, h) \
2
  do { \
3
    asm("\tpsect eeprom_data,class=EEDATA,delta=2,space=2"); \
4
    asm("\tdb\t" ___mkstr(a) "," ___mkstr(b) "," ___mkstr(c) "," ___mkstr(d) "," \
5
    ___mkstr(e) "," ___mkstr(f) "," ___mkstr(g) "," ___mkstr(h)); \
6
  } while(0)

von Rolf Magnus (Gast)


Lesenswert?

Michael S. schrieb:
> Kann mir bitte jemand erklären, wie dieses Macro zu verstehen ist, also
> was da genau gemacht wird?

Es werden zwei Zeilen Assembler-Code eingefügt. Die zweite definiert mit 
dem Assembler-Schlüsselwort "db" ("define byte") Variablen mit den an 
das Makro übergebenen Werten.

> Und wieso nach dem ersten asm(); ein Semikolon hinkommt und nach dem
> zweiten nicht?

Ein Makro macht reine Textübersetztung. Was wird dann aus einem Aufruf:
1
    __EEPROM_DATA(1, 2, 3, 4, 5, 6, 7, 8);
?
Die Regel deute ich so, daß gewünscht ist, die Parameter bei der 
Benutztung nochmal in ein Klammernpaar zu setzen:
1
    asm("\tdb\t" ___mkstr((a)) "," ___mkstr((b)) "," ...

von Michael S. (michael8192)


Lesenswert?

Uwe S. schrieb:
> ein Tipp, was passiert bei ?__EEPROM_DATA(a, b, c, d, e, f, g, h);

Das Semikolon hinter die #define Anweisung?
1
#define __EEPROM_DATA(a, b, c, d, e, f, g, h); \
2
...

Da passiert irgendwie nichts. Die do-while Schleife generiert einen 
Compilerfehler

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Uwe S. schrieb:

> Und wie wäre es das Macro etwas abzuändern:
>
1
> #define __EEPROM_DATA(a, b, c, d, e, f, g, h) \
2
>   do { ...
3
>   } while(0)
4
>

So wie das Makro aussieht wird es eingesetzt um globale asm zu 
erzeugen, d.h. außerhaub von Funktionen. Das do/while führt dann zu 
einen Syntaxerror.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rolf Magnus schrieb:
> Die Regel deute ich so, daß gewünscht ist, die Parameter bei der
> Benutztung nochmal in ein Klammernpaar zu setzen:

So lese ich das auch, wobei mir nicht ganz klar ist, warum sie das
anmosern, denn "each instance" der Parameter besitzt ja bereits ein
umschließendes Klammerpaar.

von Uwe (de0508)


Lesenswert?

Michael S. schrieb:
> Uwe S. schrieb:
>> ein Tipp, was passiert bei ?__EEPROM_DATA(a, b, c, d, e, f, g, h);
>
> Das Semikolon hinter die #define Anweisung?
>
1
> #define __EEPROM_DATA(a, b, c, d, e, f, g, h); \
2
> ...
3
>

Nein das habe ich nicht geschrieben.

> Da passiert irgendwie nichts. Die do-while Schleife generiert einen
> Compilerfehler

Das MACRO ist fast das selbe, zumindest die Codeerzeugung.

Zeige bitte deinen kompletten Code und die Meldungen.

von Michael S. (michael8192)


Lesenswert?

Also das zusätzliche Klammernpaar hat keine Auswirkungen.
Rolf Magnus schrieb:
> Die Regel deute ich so, daß gewünscht ist, die Parameter bei der
> Benutztung nochmal in ein Klammernpaar zu setzen:    asm("\tdb\t"
> ___mkstr((a)) "," ___mkstr((b)) "," ...

Ich habe bei dem zweiten asm() das Semikolon eingefügt, dafür kann ich 
bei Verwendung des Macros das Semikolon weglassen. Ich schreibe nun z.B.
1
__EEPROM_DATA( 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 )                                    /*Initialisierung EEPROM uC Addr. 0x28-0x2F                                                       */
und nicht
1
__EEPROM_DATA( 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 );                                    /*Initialisierung EEPROM uC Addr. 0x28-0x2F                                                       */

Uwe S. schrieb:
>> Das Semikolon hinter die #define Anweisung?
>>> #define __EEPROM_DATA(a, b, c, d, e, f, g, h); \
>> ...
>>
> Nein das habe ich nicht geschrieben.

Äm ja sorry, ich habs grad gesehen. Du meinst den Aufruf des Macros. Ja 
so wie Du das geschrieben hast wird den EEPROM-Zellen 0x00-0x07 der Wert 
1-8 zugewiesen.

Uwe S. schrieb:
> Zeige bitte deinen kompletten Code und die Meldungen.

Leider darf ich den Code nicht veröffentlichen. Aber die relevanten 
Stellen sind ja die Definition im Headerfile und die Verwendung im 
Mainfile:
1
/*Headerfile header.h*/
2
#ifndef _EERPOMSIZE
3
#define     _EERPOMSIZE     256
4
#endif
5
6
#define     __EEPROM_DATA( a, b, c, d, e, f, g, h )                                                                                                                                                      \
7
                asm( "\tpsect eeprom_data,class=EEDATA" );                                                                                                                                               \
8
                asm( "\tdb\t"___mkstr( (a) )","___mkstr( (b) )","___mkstr( (c) )","___mkstr( (d) )","___mkstr( (e) )","___mkstr( (f) )","___mkstr( (g) )","___mkstr( (h) ) );
1
/*mainfile main.c*/
2
....
3
#include "header.h"
4
....
5
__EEPROM_DATA( 'T', 'E', 'S', 'T', 0x00, 0x00, 0x66, 0xD0 )                                        /*Initialisierung EEPROM uC Addr. 0x00-0x07                                                       */
6
__EEPROM_DATA( 0x90, 0xD0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00 )                                    /*Initialisierung EEPROM uC Addr. 0x08-0x0F                                                       */
7
__EEPROM_DATA( 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 )                                    /*Initialisierung EEPROM uC Addr. 0x10-0x17                                                       */
8
__EEPROM_DATA( 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 )                                    /*Initialisierung EEPROM uC Addr. 0x18-0x1F                                                       */
9
__EEPROM_DATA( 0x96, 0x69, 0x33, 0x00, 0x00, 0xA5, 0x5A, 0xCC )                                    /*Initialisierung EEPROM uC Addr. 0x20-0x27                    */
10
__EEPROM_DATA( 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 )                                    /*Initialisierung EEPROM uC Addr. 0x28-0x2F                                                       */
11
__EEPROM_DATA( 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 )                                    /*Initialisierung EEPROM uC Addr. 0x30-0x37                                                       */
12
__EEPROM_DATA( 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 )                                    /*Initialisierung EEPROM uC Addr. 0x38-0x3F                                                       */
13
__EEPROM_DATA( 0xCC, 0x5A, 0xA5, 0x00, 0x00, 0x33, 0x69, 0x96 )                                    /*Initialisierung EEPROM uC Addr. 0x40-0x47                   */
14
....
15
void main (void)
16
{
17
   while(1U)
18
   {
19
   }
20
}
Und soweit funktioniert das Alles problemlos.

von Karl H. (kbuchegg)


Lesenswert?

Michael S. schrieb:

> Ich habe bei dem zweiten asm() das Semikolon eingefügt, dafür kann ich
> bei Verwendung des Macros das Semikolon weglassen. Ich schreibe nun z.B.

Finde ich nicht gut.

Mich würde das ehrlich gesagt irritieren, wenn im eigentlichen Code 
etwas vorkommt, an dessen Ende man eigentlich ein ';' aus 
Konsistenzgründen erwarten würde, wo aber keines steht, weil es schon 
vom Makro kommt.
1
#define DEF_VARIABLE(x)  double x;
2
3
int main()
4
{
5
  int i;
6
  DEF_VARIABLE( h )
7
8
  i = 8;

Das sieht irgendwie seltsam aus. Das 'fehlende' ; in main irritiert 
mich.

So hingegen
1
#define DEF_VARIABLE(x)  double x
2
3
int main()
4
{
5
  int i;
6
  DEF_VARIABLE( h );
7
8
  i = 8;

sieht die Variablendefinition in main genau so aus, wie alle anderen 
auch.
Selbst wenn das alles im Endeffekt in beiden Versionen nach der 
Textersetzung aufs gleiche rausläuft
1
int main()
2
{
3
  int i;
4
  double h;
5
6
  i = 8;
sieht die 2.te Version in gewisser Weise vertrauter aus, als die erste 
in der das ; im Makro steckt.

Tip: Bei Makros orientiert man sich an der verwendenden Stelle. Die 
soll/muss vernünftig aussehen und nicht das Makro an sich. Der 
Makroinhalt ist nur eine Textersetzung. Mehr nicht. Text A wird durch 
Text B ersetzt. Dann muss natürlich was Korrektes nach der Ersetzung 
rauskommen, aber auch Text A soll sich an die üblichen und erwarteten 
Gepflogenheiten der Sprache halten.

Wenn du globale Variablen so definierst
1
int a, b, c, d;

dann sehe ich nicht ein, warum das bei
1
EEPROM_DATA e, f, g
nicht so sein soll, dass die Definition mit einem ; endet bzw. enden 
muss.

von Michael S. (michael8192)


Lesenswert?

Karl Heinz schrieb:
> Finde ich nicht gut.
>
> Mich würde das ehrlich gesagt irritieren, wenn im eigentlichen Code
> etwas vorkommt, an dessen Ende man eigentlich ein ';' aus
> Konsistenzgründen erwarten würde, wo aber keines steht, weil es schon
> vom Makro kommt.

Da stimme ich Dir zu. Allerdings wenn ich das Macro wie vorgesehen 
verwende bekomme ich eine andere Fehlermeldung:

[ MISRA 14.3 ] Before preprocessing, a null statement shall only occur 
on a line by itself; it may be followed by a comment provided that the 
first character following the null statement is a white-space character.

D.h. MISRA wertet den Ausdruck __EEPROM_DATA (1,2,3,4,5,6,7,8); quasi 
als "Kommentar vor einem Semikolon".
Ich habe schon beide Varianten ausprobiert. Dein Beispiel:

Karl Heinz schrieb:
> #define DEF_VARIABLE(x)  double x;
>
> int main()
> {
>   int i;
>   DEF_VARIABLE( h )
>
>   i = 8;
lässt mich vermuten, dass in der Definition beim zweiten asm() das ";" 
weggelassen wurde, um dann bei der Verwendung des Macros das ";" 
erforderlich zu machen? Naja damit könnte ich leben, denn ich nutze das 
Macro nur am Anfang, um Werte zu initialisieren.

Aber was ist mit den Klammern? Hat irgendjemand eine Idee?
Ich habe auch schon sowas probiert, erhalte dann aber einen 
Compilerfehler:
1
#define    __EEPROM_DATA( a, b, c, d, e, f, g, h )                                                                             \
2
{\
3
    {\
4
        asm( "\tpsect eeprom_data,class=EEDATA" );  \
5
    }\
6
    {\
7
        asm( "\tdb\t"___mkstr( (a) )","___mkstr( (b) )","___mkstr( (c) )","___mkstr( (d) )","___mkstr( (e) )","___mkstr( (f) )","___mkstr( (g) )","___mkstr( (h) ) )\
8
    }\
9
}

von Karl H. (kbuchegg)


Lesenswert?

Michael S. schrieb:

> Da stimme ich Dir zu. Allerdings wenn ich das Macro wie vorgesehen
> verwende bekomme ich eine andere Fehlermeldung:
>
> [ MISRA 14.3 ] Before preprocessing, a null statement shall only occur
> on a line by itself; it may be followed by a comment provided that the
> first character following the null statement is a white-space character.
>
> D.h. MISRA wertet den Ausdruck __EEPROM_DATA (1,2,3,4,5,6,7,8); quasi
> als "Kommentar vor einem Semikolon".

Das kann ich mir ehrlich gesagt nicht vorstellen, das das als Kommentar 
gewertet werden würde. Wenn dem so wäre, dann würde dein MISRA Checker 
praktisch gesehen überhaupt nichts vernünftig überprüfen, denn das ist 
absolut gang und gäbe, die Sache genau so zu machen wie vorgeschlagen.

Ich habe eher den Verdacht, dass du dirch durch deine 
Makro-Umgestaltungs-Fetisch irgendwas eingehandelt hast, womit der MISRA 
Checker nicht gerechnrt hat.


> Ich habe schon beide Varianten ausprobiert. Dein Beispiel:
>
> Karl Heinz schrieb:
>> #define DEF_VARIABLE(x)  double x;
>>
>> int main()
>> {
>>   int i;
>>   DEF_VARIABLE( h )
>>
>>   i = 8;
> lässt mich vermuten, dass in der Definition beim zweiten asm() das ";"
> weggelassen wurde, um dann bei der Verwendung des Macros das ";"
> erforderlich zu machen?

Ja klar.
Das ist der absolut übliche Weg, wie das Millionen C-Programmierer 
weltweit machen.

> Aber was ist mit den Klammern? Hat irgendjemand eine Idee?
> Ich habe auch schon sowas probiert, erhalte dann aber einen
> Compilerfehler:
>
1
> #define    __EEPROM_DATA( a, b, c, d, e, f, g, h ) 
2
> \
3
> {\
4
>     {\
5
>         asm( "\tpsect eeprom_data,class=EEDATA" );  \
6
>     }\
7
>     {\
8
>         asm( "\tdb\t"___mkstr( (a) )","___mkstr( (b) )","___mkstr( (c) 
9
> )","___mkstr( (d) )","___mkstr( (e) )","___mkstr( (f) )","___mkstr( (g) 
10
> )","___mkstr( (h) ) )\
11
>     }\
12
> }
13
>

'Ich erhalte einen Compilerfehler' ist keine vernünftige Aussage, mit 
der man arbeiten kann.
Der COmpiler schreibt nicht einfach nur 'Fehler' hin, sondern liefert 
einen Fehlertext. Manchmal ist der Text missverständlich und nicht 
zielführend aber meistens gibt der schon ganz gute Hinweise, wo das 
Problem liegt oder weist einem zumindest die Richtung.

von Karl H. (kbuchegg)


Lesenswert?

Michael S. schrieb:

> Ich habe auch schon sowas probiert, erhalte dann aber einen
> Compilerfehler:
>
1
> #define    __EEPROM_DATA( a, b, c, d, e, f, g, h ) 
2
> \
3
> {\
4
>     {\
5
>         asm( "\tpsect eeprom_data,class=EEDATA" );  \
6
>     }\
7
>     {\
8
>         asm( "\tdb\t"___mkstr( (a) )","___mkstr( (b) )","___mkstr( (c) 
9
> )","___mkstr( (d) )","___mkstr( (e) )","___mkstr( (f) )","___mkstr( (g) 
10
> )","___mkstr( (h) ) )\
11
>     }\
12
> }
13
>

BItte lass mehgr Sorgfalt walten, wenn du Code hier einkopierst.
Wo genau steht der erste \?
Steht der in der selben Zeile wie das #define (und ist dort das letzte 
Zeichen der Zeile) oder ist dem nicht so?

Der \ am Ende einer Zeile zeigt dem Präprozessor an, dass das Makro noch 
nicht fertig definiert ist, sondern das da noch eine Zeile dazu gehört. 
Du kannst die nicht einfach weglassen. Denn sobald der Präprozessor auf 
eine Zeile stösst, die nicht an letzter Position in der Zeile einen \ 
enthält, ist für ihn die mit #define begonnene Makrodefinition zu Ende.

von Michael S. (michael8192)


Angehängte Dateien:

Lesenswert?

Ok. hier der zweite Versuch auch als Bild im Anhang, falls das mit der 
Formatierung nicht so hinhaut und die Fehlermeldung des Compilers. Er 
reklamiert die erste Verwendung des Macros
1
#define __EEPROM_DATA(a, b, c, d, e, f, g, h) \
2
{\
3
    {\
4
       asm("\tpsect eeprom_data,class=EEDATA"); \
5
    }\
6
    {\
7
       asm("\tdb\t" ___mkstr(a) "," ___mkstr(b) "," ___mkstr(c) "," ___mkstr(d) "," ___mkstr(e) "," ___mkstr(f) "," ___mkstr(g) "," ___mkstr(h))\
8
    }\
9
}

von Michael S. (michael8192)


Angehängte Dateien:

Lesenswert?

Und hier noch die MISRA-Regelverletzung (Ich habe jetzt im Macro das ";" 
beim zweiten asm() wieder entfernt, also alles original aus PIC18.h
Der Macroaufruf erfolgt jetzt mit ";"

von Mark B. (markbrandis)


Lesenswert?

Eine MISRA-Regelverletzung und ein Compilerfehler sind nicht dasselbe. 
Zumindest in sehr vielen Fällen nicht.

von Karl H. (kbuchegg)


Lesenswert?

Michael S. schrieb:
> Ok. hier der zweite Versuch auch als Bild im Anhang, falls das mit der
> Formatierung nicht so hinhaut und die Fehlermeldung des Compilers. Er
> reklamiert die erste Verwendung des Macros

Zeig mal die verwendende Stelle

>
1
> #define __EEPROM_DATA(a, b, c, d, e, f, g, h) \
2
> {\
3
>     {\
4
>        asm("\tpsect eeprom_data,class=EEDATA"); \
5
>     }\
6
>     {\
7
>        asm("\tdb\t" ___mkstr(a) "," ___mkstr(b) "," ___mkstr(c) "," 
8
> ___mkstr(d) "," ___mkstr(e) "," ___mkstr(f) "," ___mkstr(g) "," 
9
> ___mkstr(h))\
10
>     }\
11
> }
12
>

Die { } machen mich stutzig.

Ein
1
int i;
2
3
{
4
  int j;
5
}
6
7
int main()
8
{
9
  ...
10
}

ist in C nicht zulässig. Würde mich wundern, wenn das bei deinem 
Compiler anders wäre, wenn da innerhalb der { } ein paar Assembler 
Anweisungen stehen.


Wäre folgendes mit deinem Compiler zulässig?
1
int i;
2
3
{
4
  {
5
    asm("\tpsect eeprom_data,class=EEDATA");
6
  }
7
  {
8
    asm("\tdb\t 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55");
9
  }
10
}
11
12
int main()
13
{
14
}

Aus dem Bauch raus würde ich sagen: nein.
Das sieht überhaupt nicht nach gültigen C aus. Die Einklammerung in { } 
kann an dieser Stelle in normalem C nicht sein.
Genau das würde aber enstehen, wenn man dein Makro auf
1
int i;
2
3
__EEPROM_DATA( 0xAA, 0x55,  0xAA, 0x55,  0xAA, 0x55,  0xAA, 0x55 );
4
5
int main()
6
{
7
}
los lässt und der Präprozessor die Textersetzung gemacht hat.

von Karl H. (kbuchegg)


Lesenswert?

Mark Brandis schrieb:
> Eine MISRA-Regelverletzung und ein Compilerfehler sind nicht dasselbe.
> Zumindest in sehr vielen Fällen nicht.

Und dieses MISRA Zeugs ist mir ehrlich gesagt sowas von wurscht.
Ordentlich C lernen ist 1000 mal besser als dieses 
'Pseudo-Sicherheitsnetz' MISRA. Einige Checks sind ja ganz ok, aber 
sobald man das als Religion sieht "Ich mach MISRA und darum kann mir 
nichts mehr passieren sobald der Checker nichts mehr anmeckert", dann 
hat man irgendwas ganz krass nicht verstanden.

von Michael S. (michael8192)


Lesenswert?

Karl Heinz schrieb:
> Zeig mal die verwendende Stelle
1
__EEPROM_DATA( 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 );

Karl Heinz schrieb:
> Wäre folgendes mit deinem Compiler zulässig?int i;
>
> {
>   {
>     asm("\tpsect eeprom_data,class=EEDATA");
>   }
>   {
>     asm("\tdb\t 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55");
>   }
> }
>
> int main()
> {
> }
Nein, das funktioniert so nicht.

Aber egal es funktioniert so oder so nicht mit meiner Klammervariante. 
Frage: WIE definiert man so ein Macro mit asm's() richtig (mit Klammern) 
so dass die MISRA-Regelverletzung (14.3) nicht entsteht? Ich habe solche 
Macros bisher nur angewendet und nicht neu definieren müssen.

von Karl H. (kbuchegg)


Lesenswert?

Michael S. schrieb:
> Karl Heinz schrieb:
>> Zeig mal die verwendende Stelle
>
>
1
> __EEPROM_DATA( 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 );
2
>
>
> Karl Heinz schrieb:
>> Wäre folgendes mit deinem Compiler zulässig?int i;
>>
>> {
>>   {
>>     asm("\tpsect eeprom_data,class=EEDATA");
>>   }
>>   {
>>     asm("\tdb\t 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55");
>>   }
>> }
>>
>> int main()
>> {
>> }
> Nein, das funktioniert so nicht.

Und was wunderst du dich dann?

Du scheinst immer noch nicht verinnerlicht zu haben, dass es sich bei 
Makros um eine Textersetzung und um nicht mehr handelt.

Wenn du schreibst
1
#define TEST1  int
2
#define TEST   schnurzipups
3
#define TEST3  ;
4
5
TEST1
6
TEST
7
TEST3
8
9
int main()
10
{
11
}

dann macht der Präprozessor als erstes die entsprechenden 
Textersetzungen. UNd erst das Ergebnis davon wird dann durch den 
C-Compiler geschleust.
Im genannten Beispiel kommt nach den Textersetzungen raus
1
int
2
schnurzipups
3
;
4
5
int main()
6
{
7
}

und das ist nach den C Regeln gültig.

Es ist gülitg, weil das was nach der Ersetzung rauskommt, gülitges C ist 
unabhängig davon, wie ich den Makrotext gestalte.
Was ich aber nicht tun kann. Ich kann nicht einfach das Makro so pimpen, 
wie mir das gefällt, wenn an der verwendenden Stelle dann nichts 
korrektes mehr rauskommt. Es mag mir wunderbar gefallen, das hier zu tun
1
#define TEST1  (int)
2
#define TEST   schnurzipups
3
#define TEST3  ;
4
5
TEST1
6
TEST
7
TEST3
8
9
int main()
10
{
11
}

weil mir das besser gefällt, wenn ich Datentypen in Klammern schreibe. 
Aber nach der Textersetzung ergibt sich dann eben dieser C-Text für den 
Compiler
1
(int)
2
schnurzipups
3
;
4
5
int main()
6
{
7
}

und das ist nun mal nicht gültig. Der Datentyp kann an dieser Stelle 
(etwas umformatiert)
1
(int) schnurzipups;
2
3
int main()
4
{
5
}

nun mal nicht in Klammern stehen, egal wie sehr mir das im Makrotext 
selber gefallen hätte.

> Frage: WIE definiert man so ein Macro mit asm's() richtig (mit Klammern)
> so dass die MISRA-Regelverletzung (14.3) nicht entsteht?

Schreibs doch mal ohne Makro hin.

Wie müsstest du das ganze schreiben, so dass dein MISRA CHecker es 
akzeptiert? Wäre der mit
1
int i;
2
3
asm("\tpsect eeprom_data,class=EEDATA");
4
asm("\tdb\t 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55");
5
6
int main()
7
{
8
}
happy? Wäre dein Compiler damit happy?

Wenn das geklärt ist, was eigentlich nach Makroersetzung rauskommen 
muss, dann kann man sich auch überlegen, wie ein Makro aussehen muss, so 
dass der Präprozessor aus diesem Makro genau diesen Zieltext erzeugt.

Bei Makros muss man oft das Pferd von hinten aufzäumen. Am Anfang steht 
die Frage: Was muss eigentlich nach der Textersetzung rauskommen?

von Mark B. (markbrandis)


Lesenswert?

Karl Heinz schrieb:
> happy? Wäre dein Compiler damit happy?

Clap along if you feel like happiness is the truth ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> Und dieses MISRA Zeugs ist mir ehrlich gesagt sowas von wurscht.

Dir schon, aber manchem Endkunden in der Industrie eben nicht.

von Dirk B. (dirkb2)


Lesenswert?

Wie ist eigentlich das ___mkstr definiert?

Etwa:
1
#define___mkstr1(x) #x
2
#define___mkstr(x) ___mkstr1(x)

Und da ist auch das #, für das du von MISRA einen Freispruch bekommst:

[ MISRA 19.10 ] In the definition of a function-like macro each instance
of a parameter shall be enclosed in parentheses unless it is used as the
operand of # or ##.

von Rolf Magnus (Gast)


Lesenswert?

Dirk B. schrieb:
> Wie ist eigentlich das ___mkstr definiert?
>
> Etwa:
> #define___mkstr1(x) #x
> #define___mkstr(x) ___mkstr1(x)
> Und da ist auch das #, für das du von MISRA einen Freispruch bekommst:
>
> [ MISRA 19.10 ] In the definition of a function-like macro each instance
> of a parameter shall be enclosed in parentheses unless it is used as the
> operand of # or ##.

Allerdings ist die Frage, ob der MISRA-Checker so schlau ist, das auch 
hinzubekommen, wenn das # nochmal hinter einem weiteren Makro steht. Die 
Regel würde ja bedeuten, daß in __mkstr(x) keine Klammer um x gemacht 
werden muß. In __EEPROM_DATA() wird aber nirgends direkt das # 
verwendet, also müßte man da theoretisch klammern. Das wird aber nicht 
funktionieren, weil nachher in dem String, der aus __mkstr() rausfällt, 
die Klammern fälschlicherweise mit enthalten sind.

von Dirk B. (dirkb2)


Lesenswert?

Wenn der MISRA-Checker das nicht hin bekommt, es aber gleichzeitig 
erlaubt, ist er eine stumpfe Waffe gegen unsauberen Code.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Michael S. schrieb:
> Und hier noch die MISRA-Regelverletzung (Ich habe jetzt im Macro das ";"
> beim zweiten asm() wieder entfernt, also alles original aus PIC18.h
> Der Macroaufruf erfolgt jetzt mit ";"

In Deinem JPG fehlt hinter dem beginnenden "/*Initialisierung......" das 
abschließende "*/". Abgeschnitten oder tatsächlich nicht vorhanden?

Die beiden asm-Statements im Makro könnte man auch mit Komma statt 
Semikolon trennen, denn dann sind die geschweiften Klammern im Makro 
überflüssig und das ganze wird lesbarer.

Beweis:
1
#include <stdio.h>
2
3
int
4
main ()
5
{
6
    if (0)
7
        printf ("Hallo "),              // <--- Hier Komma
8
        printf ("Welt\n");
9
    return 0;
10
}

EDIT: Nein, sowas mache ich nicht im C-Quellcode, aber innerhalb von 
Makros bevorzuge ich die Schreibweise mit Komma statt Semikolon. Somit 
werden mehrere Statements zu einem Statement für den Compiler. Die 
do...while-Lösung funktioniert auserdem auch nur für Makros, die 
innerhalb von Funktionen aufgerufen werden.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Die beiden asm-Statements im Makro könnte man auch mit Komma statt
> Semikolon trennen,

Nein.  Lies dir den Thread ganz durch.  Die Makros sind dafür da,
außerhalb von Funktionen zu stehen.  Dort funktioniert dein
Kommaoperator genausowenig wie ein do{}while(0).

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

> Nein.  Lies dir den Thread ganz durch.  Die Makros sind dafür da,
> außerhalb von Funktionen zu stehen.  Dort funktioniert dein
> Kommaoperator genausowenig wie ein do{}while(0).

Stimmt. Kurzschluss in der Logik ;-). Sorry.

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.