Hallo,
dafür müssen wir von hinten anfangen.
Es soll ein Makro namens
printf(...)
unter einer bestimmten Bedingung definiert/erstellt werden.
Dieses obige Makro wird nur definiert/erstellt wenn ein define namens
NO_PRINTF
existiert. Die Existensabfrage #ifdef sorgt dafür.
Also. Wenn die Zeile
#define NO_PRINTF
vorhanden ist wird obiges Makro erstellt.
Fehlt die Zeile oder wird auskommentiert wird obiges Makro nicht
erstellt.
NO_PRINTF ist von der Benennung negierte Logik. Warum auch immer.
Solche Konstrukte werden gern als Schalter vewendet um im Code
eingebaute Debugausgaben abhängig kompiliert zubekommen. Oder eben auch
nicht. Mann muss nicht jede print Zeile im Code auskommentieren und
wieder kommentieren. Oder andere Zwecke.
Veit D. schrieb:> NO_PRINTF ist von der Benennung negierte Logik. Warum auch immer.
Es schaltet printf ab, wenn es aktiviert ist.
Wie sollte es sonst heißen?
Mir scheint das Makro unsinnig zu sein.
In der ersten Zeile wird NO_PRINTF definiert.
Also ist es in der zweiten Zeile, auf jeden Fall, definiert.
Die dritte Zeile wird dann folgerichtig auch immer ausgeführt
(definiert).
...und alles bis zum endif.
Das Argument: "Ausklammern" der ersten Definition erscheint mir etwas an
den Haaren herbei gezogen. Da kann man die Definition selber genauso gut
aussperren.
Anders sieht es natürlich aus, wenn man ein Dutzend verschiedene
Dingsbumse in der if-Klammer stehen hat.
Sebastian S. schrieb:> In der ersten Zeile wird NO_PRINTF definiert.> Also ist es in der zweiten Zeile, auf jeden Fall, definiert.
Das ist denke ich Jedem klar, daher ist's auch unnötig darauf
hinzuweisen, dass das so nicht im Code steht...
> #define NO_PRINTF // Steht im betreffenden .h Fill> #ifdef NO_PRINTF // Der ganze Mist im Code wo immer er gebraucht wird> #define printf(...)> #endif /* NO_PRINTF */
@ Teo D.
Bestimmt schon mehr als 100 Mal wurde hier im Forum darauf hingewiesen,
dass der Zusammenhang, einer Codesequenz, immens wichtig ist.
Wer hat sich nicht schon öfters einen Wolf gesucht, um festzustellen, wo
in den vielen defs und undefs, was gesagt wurde.
Sebastian S. schrieb:> Da kann man die Definition selber genauso gut aussperren.
Nicht wirklich:
Wenn das definierte mehrere Zeilen umspannt
Wenn der Schalter mehrfach gebraucht wird (z.b.um stattdessen eine
alternative LED blinken zu lassen)
Wenn der Schalter zentral mit anderen gesetzt wird
Wenn parallele Schalter existieren (= oder-verknüpft)
Zudem warnt der Compiler, wenn der Schalter verschieden definiert ist,
z.b. mit 0 und ohne.
Mit der Methode bleibt der Code aber auch im Object/Exe.
Du musst immer das if (debug ....) darum basteln.
Und du kannst es nicht über das Makefile schalten.
Der Vorteil ist, du kannst es während der Laufzeit umschalten.
Aber da wäre eine spezielles printf für Log-Ausgaben besser.
Veit D. schrieb:> irgendeine if Abfrage muss man schreiben. :-)
Bei deiner Methode, musst du das bei jeder Ausgabe machen.
Beim Makro, nur bei der Makrodefinition.
Dirk B. schrieb:> Bei deiner Methode, musst du das bei jeder Ausgabe machen.> Beim Makro, nur bei der Makrodefinition.
Na, der Unterschied bei deinem Beispiel liegt doch beim Zeitpunkt der
Auswertung: Makros werden vor dem Compilerlauf aufgelöst und beinflussen
den Quellcode (und damit das Programm an sich). Eine if Verzweigung wird
zur Laufzeit ausgewertet und ist bereits Bestandteil des Programms.
Nur mal so am Rande ...
> Nur mal so am Rande ...
Kann aber beides ("gleichzeitig") gewünscht sein. Was dagegen immer
unerwünscht ist, das ist die Variante wie ganz oben das printf
"wegdefiniert" wird, denn das kann semantikverändernd sein. Und das
wiederum gibt gaaanz pöse Pugs.
HTH
MaWin schrieb:> Dirk B. schrieb:>> Bei deiner Methode, musst du das bei jeder Ausgabe machen.>> Beim Makro, nur bei der Makrodefinition.>> Na, der Unterschied bei deinem Beispiel liegt doch beim Zeitpunkt der> Auswertung: Makros werden vor dem Compilerlauf aufgelöst und beinflussen> den Quellcode (und damit das Programm an sich). Eine if Verzweigung wird> zur Laufzeit ausgewertet und ist bereits Bestandteil des Programms.>> Nur mal so am Rande ...
1. Ein Laufzeit-Vergleich mit einer Compilezeit-Konstanten wird vom
Compiler (üblicherweise) wegoptimiert.
2. Um die Compilezeit-Auswertung zu erzwingen, kann man das Ganze auch
constexpr machen. Damit ist es zur Laufzeit definitiv weg.
3. Denselben Effekt wie mit dem Makro kann man mit einer
Template-Spezialisierung erreichen.
g457 schrieb:> Was dagegen immer> unerwünscht ist, das ist die Variante wie ganz oben das printf> "wegdefiniert" wird
Woher weisst du das? Ohne den Kontext zu kennen, ist deine Behauptung
einfach nur frech, dreist, m. E. sogar dumm!
MaWin schrieb:> Wilhelm M. schrieb:>> Wo steht im Eingangspost C99?>> Wo steht C++?>> Dann wird es wohl fortran sein und ein Syntax Fehler. ;->>>
Ja, ich finde es ja auch schade, dass C seit C99 (20 Jahre!) oder auch
C11 nicht wirkliche Fortschritte gemacht hat.
MaWin schrieb:> Wilhelm M. schrieb:>> ich finde es ja auch schade>> Ich auch. Jetzt sind wir zu Zweit, und? Wie geht es weiter?
Nimmste halt auch C++ ;-)
Wilhelm M. schrieb:> MaWin schrieb:>> Wilhelm M. schrieb:>>> ich finde es ja auch schade>>>> Ich auch. Jetzt sind wir zu Zweit, und? Wie geht es weiter?>> Nimmste halt auch C++ ;-)
Ich nehme was richtiges. C und seine Ableger - wie C++ - kommen nur auf
ausdrücklichen Wunsch zum Einsatz.
Hallo,
ich habe das gleich einmal in meiner Arduino IDE probiert mit einem
spezialisierten template. Allerdings kompiliert das nicht und weiß nicht
warum.
1
no matching function for call to 'debugging(Debug&)'
2
| debugging (debugMode);
1
enumclassDebug:uint8_t{RELEASE,DEBUG};
2
DebugdebugMode=Debug::DEBUG;
3
4
voidsetup(void){
5
Serial.begin(9600);
6
}
7
8
voidloop(void){
9
debugging(debugMode);
10
}
11
12
template<DebugT>
13
voiddebugging()
14
{
15
if(T==Debug::DEBUG){
16
Serial.println("Debugausgabe");
17
}
18
}
Meine Denkweise.
Der Datentyp heißt Debug.
Die Variable debugMode mit dem Datentyp Debug hat den Wert Debug::DEBUG.
Ich übergebe die Variable debugMode der Funktion debugging als
Parameter.
Das template ist mittels Datentyp <Debug T> spezialisiert.
Danach erfolgt nur noch der Vergleich.
Wo ist mein Denkfehler?
Veit D. schrieb:> Hallo,>> ich habe das gleich einmal in meiner Arduino IDE probiert mit einem> spezialisierten template. Allerdings kompiliert das nicht und weiß nicht> warum.> Die Variable debugMode mit dem Datentyp Debug hat den Wert Debug::DEBUG.> Ich übergebe die Variable debugMode der Funktion debugging als> Parameter.
Du hast aber keine Funktion mit der entsprechenden Signatur.
> Das template ist mittels Datentyp <Debug T> spezialisiert.
Du hast nur ein allg. template und keine Spezialisierung.
> Wo ist mein Denkfehler?
Ich denke, es fehlen die Grundlagen zu templates.
non-type-template-parameter müssen Compilezeit-Konstanten sein, denn sie
parametrieren ja einen Datentyp.
1
constDebugdebugMode=Debug::DEBUG;
2
3
template<DebugT>
4
voiddebugging(){
5
if(T==Debug::DEBUG){
6
}
7
}
8
9
intmain(){
10
debugging<debugMode>();
11
}
So compiliert der Code, aber was willst Du damit erreichen? Den oben
beschriebenen gewünschten Effekt doch nicht. Wie soll Deine Funktion
variable Texte ausgeben? Oder wie möchtest Du das gestalten?
Veit D. schrieb:> Hallo,>> ich habe das gleich einmal in meiner Arduino IDE probiert mit einem> spezialisierten template.
Wenn es nur um das Abschalten der Ausgabe geht, kann man es natürlich
auch ganz ohne templates lösen.
Hallo,
ich wollte das machen und auf die Magie von template hoffen.
1
// 1746/194 Bytes
2
3
enumclassDebug:uint8_t{RELEASE,DEBUG};
4
constDebugdebugMode=Debug::DEBUG;
5
6
template<classT>
7
voiddebugging(Tmode)
8
{
9
if(mode==Debug::DEBUG){
10
Serial.println("Debug");
11
}
12
}
13
14
voidsetup(void){
15
Serial.begin(9600);
16
debugging(debugMode);
17
}
18
19
voidloop(void){
20
21
}
oder mit Spezialisierung
1
// 1746/194 Bytes
2
3
enumclassDebug:uint8_t{RELEASE,DEBUG};
4
constDebugdebugMode=Debug::DEBUG;
5
6
template<Debugmode>
7
voiddebugging()
8
{
9
if(mode==Debug::DEBUG){
10
Serial.println("Debug");
11
}
12
}
13
14
voidsetup(void){
15
Serial.begin(9600);
16
debugging<debugMode>();
17
}
18
19
voidloop(void){
20
21
}
Beide Varianten verbrauchen jedoch gleich viel Flash/Ram. Das alles ohne
template verbraucht genau den gleichen Flash/Ram. Was mich jetzt
wundert. Entweder kann das der Compiler auch so schon wegoptimieren und
das ist alles schon optimal. Oder die Magie von template greift noch
nicht.
Veit D. schrieb:> Beide Varianten verbrauchen jedoch gleich viel Flash/Ram. Das alles ohne> template verbraucht genau den gleichen Flash/Ram. Was mich jetzt> wundert. Entweder kann das der Compiler auch so schon wegoptimieren und> das ist alles schon optimal. Oder die Magie von template greift noch> nicht.
Wie ich oben schon schrieb: jeder Compiler wird ein Laufzeit-if mit
einer Konstanten wegoptimieren.
Und auf welche zusätzliche Magie hast Du gehofft?
Es ging ja auch darum, ohne viel Schreibarbeit beliebigen Text
auszugeben. Das ist mit Deinem Ansatz so noch nicht möglich.
Jenachdem, ob ich debug_print_stdout.c dazulinke oder nicht, hab ich
dann debug ausgaben, oder auch nicht. Auf nem richtigen PC kann man die
debug_print_stdout.c aber auch als shared library preloaden, wenn man
die mit -fPIC kompiliert hatte. Gibt aber diverse variationen davon.
Wilhelm M. schrieb:> Ich sehe immer noch keine template-spezialisierung.
Ich meine das ist doch die template Spezialisierung. Exakter Datentyp
wird vorgegeben statt allgemeiner typename/class. Das template kann nur
mit diesen Datentyp gebaut werden. Wie sieht bei dir ein spezialisiertes
Funktions-Template aus?
1
template<Debugmode>
2
voiddebugging()
3
{
4
...
5
}
Wegen der erhofften Magie. Ja stimmt, wenn ich alles außer der
Serial.print Zeile auskommentiere bleiben auch 1746/194 Bytes stehen.
Weniger geht also nicht.
Veit D. schrieb:> Wilhelm M. schrieb:>> Ich sehe immer noch keine template-spezialisierung.>> Ich meine das ist doch die template Spezialisierung.
Nein.
> Exakter Datentyp> wird vorgegeben statt allgemeiner typename/class. Das template kann nur> mit diesen Datentyp gebaut werden.
Du hast einfach ein allg. template mit einem
non-type-template-parameter.
> Wie sieht bei dir ein spezialisiertes> Funktions-Template aus?
Nicht nur bei mir ;-)
Schnapp Dir ein Buch und liest mal nach ...
z.B.:
https://www.amazon.de/Templates-Complete-Guide-David-Vandevoorde/dp/0321714121>
1
>template<Debugmode>
2
>voiddebugging()
3
>{
4
>...
5
>}
6
>
Ein Spezialisierung setzt ein allg. template voraus und definiert dann
eine Ausnahme zum allg. Fall für spezielle DT oder Konstanten.
Etwa:
Hallo,
Danke für das Bsp. und Erklärung. Ich stelle fest das ich den Begriff
"Spezialisierung" anders aufgefasst und verstanden habe. Das template in
deinem Bsp. bleibt unspezifiert - template eben. Nur der Aufruf wird
spezialisiert.
Wenn ich das template betrachte kann ich keine Spezialisierung erkennen,
eben weil es allgmein bleibt. Das ist mein Gedankenproblem. Denn ein
allgemeines template soll ja für alle Datentypen verwendbar sein,
deswegen kann ein allgemeines template in meinen Augen nicht
spezialisiert sein. Kannst du mir gedanklich folgen?
Jetzt weiß ich das der Aufruf mit konkreten Datentypen die
Spezialisierung ist. Halte ich zwar immer noch für etwas seltsam bzw.
die Formulierung ist seltsam, weil das der Standardfall ist und deswegen
in meinen Augen keine Spezialisierung sein kann. Aber nun gut, es ist
wie es ist.
Wegen dem Buch. Gibt es ein gutes template Buch auch in deutsch? Hast du
eine Empfehlung? Möchte nicht dumm sterben. :-) Habe bedenken das
sich zusätzliche Probleme mit meiner Übersetzung einschleichen.
Eric B. schrieb:> Oder einfach in C99:> #ifdef DEBUG> #define debug(...) printf(_VA_ARGS_)
Warum einfach und universell, wo es denn doch auch in nur C++ und
laenger geht, wobei man nicht genau weiss, bei welcher Optimierung
welcher Compiler das ev. wegoptimieren darf und kann ;-)
leo
Hallo,
das habe ich mich auch schon öfters gefragt. :-)
Aber wenn man das in C++ nicht auf die Spitze treibt und einfach hält,
hält man sich von den Fallstricken der #defines und sein Gevolke fern,
womit andere Probleme lauern. Die Welt ist nicht perfekt. :-)