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
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:
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.
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.
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.
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:
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
intmain()
4
{
5
inti;
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
intmain()
4
{
5
inti;
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
intmain()
2
{
3
inti;
4
doubleh;
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
inta,b,c,d;
dann sehe ich nicht ein, warum das bei
1
EEPROM_DATAe,f,g
nicht so sein soll, dass die Definition mit einem ; endet bzw. enden
muss.
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:
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:>
'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.
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.
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
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 ";"
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
>
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?
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
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.
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.
>> 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
intmain()
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
intmain()
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
intmain()
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
intmain()
6
{
7
}
und das ist nun mal nicht gültig. Der Datentyp kann an dieser Stelle
(etwas umformatiert)
1
(int)schnurzipups;
2
3
intmain()
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
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?
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 ##.
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.
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
return0;
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.
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).
> 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.