Hallo,
gib es für folgendes eine Möglichkeit?
Ich möchte übergreifend auf #defines zugreifen. Was mir klar ist, es
handelt sich hierbei mehr oder weniger nur um Textersetzung für den
Compiler
>>main.c
#define BAUD 9600
>>uart.h
#ifndef BAUD
#warning UART_BAUD not defined. Set UART_BAUD 9600
#define BAUD 9600
#endif
>>uart.c
void func() {if(BAUD >= 9600) ...;}
Wenn in main.c BAUD nicht definiert ist, soll er in der uart.h
entsprechend BAUD setzen.
Hain schrieb:> Hallo,>> gib es für folgendes eine Möglichkeit?
Du kannst es maximal komplett aus allen Source Code Files rausziehen und
in deinen Projektoptionen dem Compiler beim Aufruf mitgeben.
Aber: Warum lässt du dir nicht einfach in der uart_init Funktion die
gewünschte Baudrate als Parameter mitgeben? In der uart.c gibt es
eigentlich keinen wirklichen Grund, warum das als Makro verfügbar sein
müsste.
>>>uart.h> #ifndef BAUD> #warning UART_BAUD not defined. Set UART_BAUD 9600> #define BAUD 9600> #endif
wie sich immer wieder rausstellt ist das keine gute Idee. Wenn so ein
Makro nicht definiert ist, dann sollte das ernsthaft ein einen Fehler
münden und nicht in Default-Annahmen. Denn die Praxis zeigt, dass
derartige Warnungen leider immer wieder einfach ignoriert werden. Mit
allen daraus folgenden Konsequenzen.
ja zb so:
main.h:
#define BAUD 9600
#include "uart.h"
main.c:
#include main.h
oder auch so:
main.c:
#define BAUD 9600
#include "uart.h"
oder so:
main.h:
#define BAUD 9600
main.c:
#include "main.h"
#include "uart.h"
manchen Compilern ist es sogar Powidl was zuerst inkludiert oder
definiert wird.
Karl Heinz schrieb:> Du kannst es maximal komplett aus allen Source Code Files rausziehen und> in deinen Projektoptionen dem Compiler beim Aufruf mitgeben.
Das ist dann wirklich von Compiler zu Compiler unterschiedlich. Meiner
Frisst das alles und manchmal sogar zuviel.
(uvision)
letztens hatte ich z:b. das Problem dass ein vollständig aufgelöstes
Makro nach #undef und #define wieder zum Makro wird.
dotm schrieb:> manchen Compilern ist es sogar Powidl was zuerst inkludiert oder> definiert wird.
Würde mich sehr wundern, da es das ganze wohldefinierte Konzept
durcheinanderbrächte.
Hier, wie ich es lösen würde:
config.h
1
#ifndef CONFIG_H
2
#define CONFIG_H
3
#include "chip_specific_headerfile.h"
4
5
#define UART_BAUDRATE 9600 //"BAUD" finde ich doof, da es noch andere peripherals geben koennte
#ifndef UART_H
#define UART_H
Was bedeutet das eigentlich, wird dauerhaft mit angelegt. Ich würde es
so deuten,
dass ich eine h-Datei nicht doppelt laden kann. Soll heißen, wenn
bereits bekannt, inkludiere keine weiteren Zeilen innerhalb der
Präprozessordefenition.
Exakt. Das wird auch manchmal "Include guards" genannt und hat den
Vorteil, dass eine Headerdatei nur einmal includiert wird.
Hinweis: Man muss ich vor Augen führen, dass dies immer für jede C-Datei
einzeln gilt. Im obigen Beipiel wird also sowohl uart.h als auch
config.h zweimal includiert (da ich zwei c-Dateien habe, die das tun)
Phantomix Ximotnahp schrieb:> Würde mich sehr wundern, da es das ganze wohldefinierte Konzept> durcheinanderbrächte.
Ich hab in letzter Zeit die Erfahrung gemacht dass das Verhalten des
Präprozessors sich stark unterscheidet.
Beispiel:
werte.h:
1
#define WERT_MODULA 100
2
#define WERT_MODULB 200
modula.h
1
#include"werte.h"
2
#undef MAKE(x)
3
#define MAKE(x) x+WERT_MODULA
4
5
#define TEST_MODULA MAKE(1)
modulb.h
1
#include"werte.h"
2
#undef MAKE(x)
3
#define MAKE(x) x+WERT_MODULB
4
5
#define TEST_MODULB MAKE(1)
main.c:
1
#include"modula.h"
2
#include"modulb.h"
3
4
printf("modula: %d\r",TEST_MODULA);
5
printf("modulb: %d\r",TEST_MODULB);
eclipse makroexpansion sagt
101
201
chide sagt
101
201
uvision sagt
101
101
eclipse, chide, uvision?
Das sind doch alles IDE's und haben als solche keine relevante
Entscheidungsfunktion.
Entscheidend ist, was der eigentliche Präprozessor, der bei einem
Compilerlauf zum Einsatz kommt, dazu sagt.
Ich hätte eigentlich 2 mal 201 als Ausgabe erwartet und in der Tat ist
das auch genau der Output, den man vom laufenden Programm kriegt.
Unabhängig davon, ob eine IDE mit der richtigen Reihenfolge der
Makrodefinition bedingt durch die include Reihenfolge klar kommt oder
nicht.
Karl Heinz schrieb:> Ich hätte eigentlich 2 mal 201 als Ausgabe erwartet und in der Tat ist> das auch genau der Output, den man vom laufenden Programm kriegt.> Unabhängig davon, ob eine IDE mit der richtigen Reihenfolge der> Makrodefinition bedingt durch die include Reihenfolge klar kommt oder> nicht.
ich meinte eigentlich 201 201.
Das Problem ist dass die IDE beim Codegenerieren Fehler wirft. Eventuell
macht es dann der Compiler wieder richtig. Das geht mir bei Eclipse in
Kombination mit µVision gehörig auf die Nerven. Allein schon wegen einem
zwingende return. Eclipse regt sich auf und µVision wiederum sagt
(richtigweise) statement unreacheable.
Warum eigentlich zweimal 201? Ist der Präprozessor nicht single-pass?
Dein Problem hat eigentlich nichts mit include zu tun, daher habe ich
das mal in einen Codeschnippsel zusammengefasst.
Das zweite undef + define MAKE(x) ist entscheidend für das was passiert.
Was mich auch wahsinnig macht:
char string[4] = "abcd";
chide:
ERROR: string is longer than array size
uvision nimmt es (meineserachtens korrekterweise) problemlos an
Phantomix Ximotnahp schrieb:> Das zweite undef + define MAKE(x) ist entscheidend für das was passiert.
Ich würde es so formulieren:
ENtscheidend ist, wann genau die Makroexpanion gemacht wird.
Mit einem #define wird nur gespeichert, dass eine gemacht werden soll.
Aber es wird noch nichts ersetzt. Selbst wenn im Ersetzungstext selbst
wieder ein Makro verwendet wird.
> Dein Problem hat eigentlich nichts mit include zu tun, daher habe ich> das mal in einen Codeschnippsel zusammengefasst.> Das zweite undef + define MAKE(x) ist entscheidend für das was passiert.
Liegt das daran dass ich ein Makro redefiniere? Das sollte ich
eigentlich garnicht dürften. Diese Konstrukt liefert aber das gleiche
Ergebnis:
1
#define MAKE(x) x+WERT_MAKE
2
#define WERT_MODULA 100
3
#define WERT_MODULB 200
4
5
#undef WERT_MAKE
6
#define WERT_MAKE WERT_MODULA
7
8
#define TEST_MODULA MAKE(1)
9
10
#undef WERT_MAKE
11
#define WERT_MAKE WERT_MODULB
12
13
#define TEST_MODULB MAKE(1)
14
15
uint8_taaa=TEST_MODULA;
16
uint8_tbbb=TEST_MODULB;
Würde der Präprozessor singlepass drübergehen wäre schon bei
#define TEST_MODULA MAKE(1)
Das Symbol vollständig aufgelöst. Wozu sollte sonst #undef gut sein wenn
die Reihenfolge nicht ausschlaggebend ist?
Karl Heinz schrieb:> Ich würde es so formulieren:> ENtscheidend ist, wann genau die Makroexpanion gemacht wird.
Das unterschreibe ich mal so und ist auch die Antwort auf deine Frage.
Die Makroexpansion wird offensichtlich zum Schluss gemacht
dotm schrieb:> Was mich auch wahsinnig macht:>> char string[4] = "abcd";>> chide:> ERROR: string is longer than array size>> uvision nimmt es (meineserachtens korrekterweise) problemlos an
"abcd" ist aber 5 characters lang ;-)
Immer die '\0' mit berücksichtigen!
Phantomix Ximotnahp schrieb:> Karl Heinz schrieb:>> Ich würde es so formulieren:>> ENtscheidend ist, wann genau die Makroexpanion gemacht wird.>> Das unterschreibe ich mal so und ist auch die Antwort auf deine Frage.>> Die Makroexpansion wird offensichtlich zum Schluss gemacht
Genau
Die komplette Ersetzung, bis runter zu den Zahlenwerten findet erst hier
1
uint8_taaa=TEST_MODULA;
statt. Und an dieser Stelle gelten die gerade 'akiven' Makros. So etwas
wie eine Umgebung, in der ein Makro definiert wurde, eine Bindung zur
Defintionszeit, gibt es in C nicht.
dotm schrieb:>> Dein Problem hat eigentlich nichts mit include zu tun, daher habe ich>> das mal in einen Codeschnippsel zusammengefasst.>> Das zweite undef + define MAKE(x) ist entscheidend für das was passiert.>> Liegt das daran dass ich ein Makro redefiniere?
Nein.
Es liegt daran, dass du IDE und Compiler durcheinander würfelst.
Das eine ist ein Editor, der Syntax-Highlighting bzw. Querverbindungen
im Code auswerten, macht.
Und das andere ist der C-Compiler, der sich an die normierten C-Regeln
halten muss.
Was immer dir dein Editor anzeigt .... das ist das was der Editor dir
anzeigt. Das kann identisch zu dem sein, was ein Compiler auch
ermittelt, muss es aber nicht sein.
Phantomix Ximotnahp schrieb:> "abcd" ist aber 5 characters lang ;-)>> Immer die '\0' mit berücksichtigen!
Richtig. Der Abschluss mit einem Null ist aber bei Definition optional!
dotm schrieb:> Was mich auch wahsinnig macht:>> char string[4] = "abcd";>> chide:> ERROR: string is longer than array size>> uvision nimmt es (meineserachtens korrekterweise) problemlos an
Falsch. Ein C "string" wird automatisch mit 0 abgeschlossen. Also
braucht er 5 Bytes:
1
charstring[5]="abcd";
oder einfacher
1
charstring[]="abcd";
Soll keine abschliessende 0 angehaengt werden, muss man leider
schreiben:
dotm schrieb:> Richtig. Der Abschluss mit einem Null ist aber bei Definition optional!
Ähm. Wenn du "abcd" schreibst, ist '\0' mit dabei. Auch wenn du es nicht
hingeschrieben hast. "abcd" ist 5 characters lang.
dotm schrieb:> Würde der Präprozessor singlepass drübergehen wäre schon bei>> #define TEST_MODULA MAKE(1)> Das Symbol vollständig aufgelöst.
Da ist überhaupt nichts aufgelöst.
Du dichtest dem Präprozessor Fähigkeiten an, die er nicht hat.
Wenn der Präprozessor diese #define Zeile zu Gesicht bekommt, dann trägt
er sich in seinen internen Tabellen ein, dass der Text 'TEST_MODULA' in
weiterer Folge im Source Code durch den Text 'MAKE(1)' zu ersetzen ist.
Mehr passiert da nicht.
> Wozu sollte sonst #undef gut sein
Dann schmeisst der Präprozessor aus seinen internen Tabellen wieder
raus, dass es einen Ersetzungstext für MAKE gibt. Mehr passiert da
nicht.
Kai S. schrieb:> dotm schrieb:>> Was mich auch wahsinnig macht:>>>> char string[4] = "abcd";>>>> chide:>> ERROR: string is longer than array size>>>> uvision nimmt es (meineserachtens korrekterweise) problemlos an>> Falsch. Ein C "string" wird automatisch mit 0 abgeschlossen.
Nicht ganz
1
charc[4]="abcd";
ist tatsächlich korrekt. In diesem Fall findet keine automatische
Terminierung mit einem '\0' Byte im Array statt.
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
6.7.8 - 14, auf Seite 126
Entscheidend ist der Passus "if there is room"
Phantomix Ximotnahp schrieb:> Ähm. Wenn du "abcd" schreibst, ist '\0' mit dabei. Auch wenn du es nicht> hingeschrieben hast. "abcd" ist 5 characters lang.
1
There is one special case where the null character is not automatically appended to the array. This case is when the array size is explicitly specified and the number of initializers completely fills the array size. For example:
2
3
char c[4] = "abcd";
http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/V40F_HTML/AQTLTBTE/DOCU_046.HTMKarl Heinz schrieb:> Da ist überhaupt nichts aufgelöst.> Du dichtest dem Präprozessor Fähigkeiten an, die er nicht hat.> Wenn der Präprozessor diese #define Zeile zu Gesicht bekommt, dann trägt> er sich in seinen internen Tabellen ein, dass der Text 'TEST_MODULA' in> weiterer Folge im Source Code durch den Text 'MAKE(1)' zu ersetzen ist.> Mehr passiert da nicht.
Leider hast du da vollkommen recht. Das Problem ist dass dieses
Verhalten nirgendwo dokumentiert ist. Dann Programmiere ich freudig vor
mich dahin weil mir der Eclipse Indexer das Blaue vom Himmel verspricht
und bekomme dann vom Compiler den Hammer drüber.
Hast du das irgendwo schriftlich?
Kai S. schrieb:> Karl Heinz schrieb:>> http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf>> 6.7.8 - 14, auf Seite 126>> Entscheidend ist der Passus "if there is room">> Wow. Man lernt nie aus :-)>> ZigZeg
Dito.
Ich kann mir auch schon genau vorstellen, wieso diese Ausnahme so
definiert ist. Weil es sonst jedem zweiten Entwickler mal passiert wäre,
ein Byte zu wenig definiert zu haben, was dann einem Buffer Overflow
gleichkommt :D Allerdings ist ein unterminierter C-String auch nicht
wirklich schön. Nur beim Debuggen merkt man den schneller...
propagierst.
Der springende Punkt ist aber, dass in C die Unterscheidung zwischen
Strings und Bytefeldern sich im Prinzip nur an dieser \0 Terminierung
stösst.
Mittels
1
charc[4]="abcd";
definiert man sich im Grunde ein Bytefeld bekannter Länge, in dem
bestimmte Werte stehen. c als String aufzufassen, wäre vom Konzept her
recht fatal. In so einem Fall sind alle str.... Funktionen tabu und
müssen durch die entsprechenden mem.... Funktionen ersetzt werden.
(Ich bin vielleicht nicht repräsentativ. Aber IMHO braucht so eine
Initialisierung wirklich niemand. Das ist nur eine Stolperfalle, wie so
einige andere 'obskure' C Regeln auch. Aber ... damit muss man leben.)
Karl Heinz schrieb:> Mittels char c[4] = "abcd";> definiert man sich im Grunde ein Bytefeld bekannter Länge, in dem
Ich mache damit dann noch wesentlich schwindlichere Konstruke wie zb
einen uint32_t pointer drübercasten um damit einen schnellen
Konsolencommandodecoder zu realisieren. Ist sicher alles nicht ganz
koscher aber dafür halt sehr flott am MCU. Und wenn da steht ich darf
das dann will ich auch dass der Compiler die Schnauze hält und pariert
:)
dotm schrieb:> koscher aber dafür halt sehr flott am MCU. Und wenn da steht ich darf> das dann will ich auch dass der Compiler die Schnauze hält und pariert> :)
Oooch. Der Compiler hält da normalerweise schon die Schnauze.
Aber die Parsing-Fähigkeiten diverser Editoren zum Syntax-Highlighting
bzw. für andere Komfort-Funktionen, lassen dann eben des öfteren zu
wünschen übrig.
Bei einem Compiler ist das recht einfach zu gewährleisten. Jeder
Hersteller hat da seine umfangreichen Sammlung an "Testprogrammen", die
durch den Compiler gehen müssen. Ehe ein Compiler raus geht, muss er
sich da normalerweise erst mal stundenlang mit diesen Tests
beschäftigen, die sich auch gut auswerten lassen. Das stellt zum einen
sicher, dass sich nicht unbemerkt Fehler in den Compiler eingeschlichen
haben die vorher nicht da waren und gewährleistet andererseits dass im
Laufe der Zeit auch noch jedes noch so obskure Stück syntaktischer
Zucker in den Compiler kommt und der Compiler zeigen muss, dass er damit
umgehen kann. Der Tei list eigentlich recht einfach automatisch zu
testen. Schwieriger ist die Qualitätskontrolle, wenn am Optimizer
Veränderungen vorgenommen werden.