Verwendung von #if und #else ?

OP #2484237
Hi,

ich schreibe für einen Tricore TC1797 in C ein Programm zum 
Sensorauswerten und bin über die Präprozessoranweisungen #if und #else 
gestoßen.
Damit kann man ja scheinbar den Code wählen, der kompiliert werden soll.

Ich habe eine C-Datei über die ich bestimmte Sachen festlegen will.
Ein Beispiel: Soll die Endwertberechnung über Filter stattfinden oder 
nicht? Dazu gibt es einen Parameter.

Im Interrupt soll dann nur der entsprechende Quellcode übersetzt werden.
Beispiel:

#if(Parameter1>0)
function1();
#else
function2();
#endif

Über die C-Datei will ich eine Vielzahl von solchen Optionen einbauen, 
mit denen man das Programm variabel machen kann. Damit nicht in jedem 
Interrupt viele if-Abfragen stattfinden, soll der Compiler nur die 
benötigten Codezeilen übersetzen.

Oder ist das #if nicht für eine solche Verwendung gedacht?
Ist es nur in Kombination mit #define konzipiert?
OP
danke, Michael H.
So richtig schlau werd ich aber nicht daraus.

Sagt der Text, dass es teilweise mit manchen Compilern nicht richtig 
geht?

Mein Code sieht z.B. folgendermaßen aus:

#if ((filterAddLength01!=0x00)||(filterMavLength01!=0x00))
put(buffer01,bufferSize01,&posPut01,FADC_uwGetFinalFilterResult(0),&n01) 
;
#else 
put(buffer01,bufferSize01,&posPut01,FADC_uwGetChannelConversionResult(0) 
,&n01);
#endif

Irgendwie scheint er dabei meistens ins else-Statement zu gehen.
Wenn ich die beiden Parameter filterAddLength01 und filterMavLength01 
auf einen anderen Wert als 0x00 setze, scheint er manchmal dieses und 
manchmal jenes zu machen.
Kann leider keinen Zusammenhang ausmachen!
... ich schreibe für einen Tricore TC1797 in C ein Programm ... Im 
Interrupt soll dann nur der entsprechende Quellcode übersetzt werden 
...

Also irgendwas passt hier nicht zusammen. Oder haue ich da ein paar 
Begriffe durcheinander?
Gast
Minty Mint schrieb:
> Mein Code sieht z.B. folgendermaßen aus:
>
> #if ((filterAddLength01!=0x00)||(filterMavLength01!=0x00))
> put(buffer01,bufferSize01,&posPut01,FADC_uwGetFinalFilterResult(0),&n01) ;
> #else
> put(buffer01,bufferSize01,&posPut01,FADC_uwGetChannelConversionResult(0) ,&n01);
> #endif

Woher kommen filterAddLength01 und filterMavLength01? Variablen oder 
#define?
OP
OK, danke für die Tipps.
Jetzt funktioniert es soweit.
Hatte filterAddLength01 als globale Variable definiert.

Hab das nun zu einem #define gemacht.

Unter dem geposteten Link hab ich nicht alles gelesen.
Wär auch recht viel.

Demnach muss man das immer über #define machen, sonst gehts nicht, oder?
Was für einen Datentyp liefern solche Defines eigentlich?
Soweit ich weiß geht das mit int und long.
Minty Mint schrieb:

> mit denen man das Programm variabel machen kann. Damit nicht in jedem
> Interrupt viele if-Abfragen stattfinden, soll der Compiler nur die
> benötigten Codezeilen übersetzen.

Wenn wie hier die abgefragten Dinge konstant sind, dann wird der 
Compiler die Abfragen bereits bei optimierten Übersetzen auflösen und 
den unmöglichen Code eliminieren.

Exzessive Verwendung von diesen Präprozessor-Direktiven ist nicht 
sonderlich übersichtlich. Wenn solcherart ausgeblendeter Code vom 
Compiler nicht akzeptiert wird, dann sind sie nötig. Andernfalls sind 
normale Abfragen weit lesbarer.
Michael H. schrieb:
> willst du mir jetz sagen, 5 und 5 seien text?

Der PP hält sie tatsächlich erstmal als Text.
Nur im Vergleich mit < wird daraus eine Zahl.

Das sieht man z.B. wenn man eine vermeintliche Zahl mit einem 
merkwürdigen Format definiert (mit führendem + bspw.) und dann wieder 
irgendwie ausgibt, z.B. über # als String: dann taucht die Zahl in ihrem 
ursprünglichen Format auf, und nicht aus einer Zahl in eine 
Standarddarstellung konvertiert.
Michael H. schrieb:
> lest die doku, sie gibt mir recht.

[...]
Formally, preprocessing numbers begin with an optional period, a 
required decimal digit, and then continue with any sequence of letters, 
digits, underscores, periods, and exponents.
[...]
The purpose of this unusual definition is to isolate the preprocessor 
from the full complexity of numeric constants.
[...]

Erst durch einen Vergleich mit #if oder #ifdef wird veranlasst, dass der 
Textschnipsel als -wie immer auch geartete- Zahl interpretiert und 
verwendet wird.
Ich klink mich aus.
Mini Float schrieb:

> Erst durch einen Vergleich mit #if oder #ifdef wird veranlasst, dass der
> Textschnipsel als -wie immer auch geartete- Zahl interpretiert und
> verwendet wird.

Und dort gilt als Daumenregel "Schrott rein Schrott raus". #if 
Statements akzeptieren als Bedingung ziemlich viel Blödsinn ohne sich 
drüber zu beschweren. Das sorgt mitunter für Irritationen, wenn etwas, 
was im "if" Statement als Syntax Error angezeigt würde, vom #if 
kommentarlos gefressen wird. Nicht immer zur Freude des Programmierers.
Gast
1
#define DEBUG
2
#ifdef DEBUG
3
//Debugmodus
4
#endif

reicht vollig und ist einfacher und deshalb auch verbreiteter (in 
sämtlichen üblichen Headerfiles z.B.).
Sebastian M. schrieb:

> so?

Im Prinzip ja, aber dies führt zu recht hässlichem Code, wenn alle paar 
Zeilen so eine #if/#endif Klammer steht.

Besser beispielsweise:
1
#if debug
2
# define TRACE(s) uart_puts(s)
3
#else
4
# define TRACE(s)
5
#endif
6

7
   ...
8
   TRACE("Debugmodus AN");
9
   ...
10
   TRACE("Panic!");

Weil man so beliebig viel Trace-Kram einstreuen kann, ohne dass es 
unübersichtich wird.

Freunde von printf können das auch ohne varargs-Makros haben:
1
#if debug
2
# define TRACE(s) printf s
3
#else
4
# define TRACE(s)
5
#endif
6

7
  ...
8
  TRACE(("Version vom %s", __DATE__));
9
  ...
Man beachte die Klammern.
Gast
>Freunde von printf können das auch ohne varargs-Makros haben:

>#if debug
># define TRACE(s) printf s
>#else
># define TRACE(s)
>#endif

Geht auch so

#if debug
# define TRACE printf
#else
# define TRACE(...)
#endif
OP
Danke für die Hilfe!

Das ist echt ein Spitzenboard hier!
Man kriegt einfach immer Antworten und eine brauchbare ist stets dabei.

Soll ich jetzt eigentlich diese #if und #else verwenden oder ist das 
sowieso hinfällig, wenn man darüber nur #defines abfragt?

prx schrieb:
"Wenn wie hier die abgefragten Dinge konstant sind, dann wird der
Compiler die Abfragen bereits bei optimierten Übersetzen auflösen und
den unmöglichen Code eliminieren.

Exzessive Verwendung von diesen Präprozessor-Direktiven ist nicht
sonderlich übersichtlich. Wenn solcherart ausgeblendeter Code vom
Compiler nicht akzeptiert wird, dann sind sie nötig. Andernfalls sind
normale Abfragen weit lesbarer."

Soll ich nun if oder #if verwenden?
Gast
Minty Mint schrieb:
> Soll ich jetzt eigentlich diese #if und #else verwenden oder ist das
> sowieso hinfällig, wenn man darüber nur #defines abfragt?

Meine Meinung: Schreibe deine Programme möglichst ohne #if und ohne 
#ifdef
Das ist Präprozessorakrobatik und dient eigentlich nur dazu, aus einigen 
ähnlichen Quellen eine einzige Quelle zu machen. Am Ende wird das alles 
nur unübersichtlich und schwerfällig. Wenn du für 2 ähnliche Probleme 2 
unterschiedliche Programme brauchst, dann mach für jedes Problem eines. 
Andererseits kann es ja vorkommen, daß dein Programm verschiedene Fälle 
beachten muß (zur Laufzeit, wohlgemerkt), dann ist #if regelrecht 
falsch.

Ich hatte schon Quellen, wo sich #ifdef .... #endif Konstrukte über 
mehrere verschiedene Quellen hinzogen, so daß man am Ende gar nicht mehr 
nachvollziehen konnte, was denn tatsächlich im erzeugten Code landete. 
Das war ein Obermist.

Ach ja, nochwas: Spaghetticode (Relikt von BASIC) und die Verwendung von 
goto_ in C sind was _verschiedenes. Also schreibe dort, wo es sachlich 
hinpaßt besser goto und vermeide sowas wie while(1){....};

W.S.
OP
hm, mir wurde 2 mal beigebracht, dass man keinesfalls goto verwenden 
soll.
deswegen stelle ich auch deine andere Antwort in Frage, W.S..

Letztendlich brauche ich für verschiedene Anwendungsfälle verschiedenen 
Code.

Die Frage ist dann: Wird bei normalem "if" auch sicher nur der nötige 
Code übersetzt oder nicht?

Oder soll ich auf Nummer sicher gehen mit #if?
Was meint ihr?
Wozu gibt es dann überhaupt die #if-Funktion, wenn der Compiler sowieso 
den überflüssigen Code wegkürzt?
W.S. schrieb:

> Ach ja, nochwas: Spaghetticode (Relikt von BASIC) und die Verwendung von
> goto_ in C sind was _verschiedenes. Also schreibe dort, wo es sachlich
> hinpaßt besser goto und vermeide sowas wie while(1){....};

Das ist mal ein recht seltsamer Tipp. Falls du das meinst
1
   loop:
2
      ...
3
      goto loop;
an Stelle des allgemein üblichen
1
   while(1) {
2
      ...
3
   }
oder
1
   for (;;) {
2
      ...
3
   }
Minty Mint schrieb:

> Die Frage ist dann: Wird bei normalem "if" auch sicher nur der nötige
> Code übersetzt oder nicht?

Ja, wenn der Compiler etwas taugt.

> Oder soll ich auf Nummer sicher gehen mit #if?

> Wozu gibt es dann überhaupt die #if-Funktion, wenn der Compiler sowieso
> den überflüssigen Code wegkürzt?

Weil es Fälle gibt, in denen man mit if() nicht weiter kommt. 
Beispielsweise bei
1
#if linux
2
  #include <linux/sonstwas.h>
3
#elif windows
4
  #include <win32.h>
5
#else
6
  #error Mac???
7
#endif
Gast
A. K. schrieb:
> Das ist mal ein recht seltsamer Tipp. Falls du das meinst

nein, er meint vermutlich soetwas:
1
while(1) {
2

3
   if ( x == y ) {
4
      beak;
5
   }
6

7
   if ( a== b) {
8
      beak;
9
   }
10
}

statt:
1
if ( x == y ) {
2
  goto next;
3
}
4

5
if ( a== b) {
6
   goto next:
7
}
8
next:
Gast
Minty Mint schrieb:
> hm, mir wurde 2 mal beigebracht, dass man keinesfalls goto verwenden
> soll.
> deswegen stelle ich auch deine andere Antwort in Frage, W.S..

Tja, sowas stimmt mich ein bissel traurig. Dir wurde es also SO 
beigebracht... hmm in meinem Inneren grummelt die Frage, ob die jungen 
Leute heutzutage etwas gelehrt bekommen, den Sinn verstanden und es 
somit gelernt haben oder ob sie lediglich dressiert bzw. abgerichtet 
werden.

Im Klartext: das Wort "goto" gehört zum Grundwortschatz von C und vieler 
anderer Programmiersprachen. Du darfst deinen Lehrern einen schönen Gruß 
von mir ausrichten und daß sie sich nach 30 jährigem Tiefschlaf mal 
aufraffen mögen, ihre Köpfe endlich auszumisten. Damals war BASIC die 
schlichtweg überragende Programmiersprache auf allem, was man heute "PC" 
nennen würde. Selbst der Ur-IBM-PC hatte zuallererst einen residenten 
Basicinterpreter drin. Da aber das damalige Basic im Wesentlichen auf 
Zeilennummern beruhte, war ein buntes Durcheinander von GOTO's 
schlichtweg nötig.

Aus dieser Zeit stammt der Rat, "goto" möglichst zu vermeiden und sich 
der anderen Konstrukte zu bedienen, die die damals aufkommenden neuen 
Programmiersprachen Pascal und C boten: case bzw. switch, do while, 
repeat until und so.

Pauschal das goto zu verteufeln und dies zu verabsolutieren ist reiner 
Unsinn. Aber offenbar wird den jungen Leuten heutzutage eben genau 
dieser Unsinn eingebleut und diese verinnerlichen das ohne es kritisch 
zu hinterfragen. Kurzum, sowas stimmt mich traurig.

W.S.
Minty Mint schrieb:
> Letztendlich brauche ich für verschiedene Anwendungsfälle verschiedenen
> Code.
und dann stellt sich halt die frage: kannst du die fälle erst zur 
laufzeit oder schon zur compilezeit unterscheiden?

> Die Frage ist dann: Wird bei normalem "if" auch sicher nur der nötige
> Code übersetzt oder nicht?
grundsätzlich: ja, wird mitübersetzt.

> Oder soll ich auf Nummer sicher gehen mit #if?
es wäre hilfreich, wenn du diese recht einfache entscheidung selbst 
fällen würdest, nachdem du denn verstanden hast, was #if und if denn nun 
sind.
#if ist eine reine präprozessoranweisung. klammerst du befehle in ein 
#if-conditional, das nicht erfüllt ist, behandelt es der compiler, als 
wäre es nicht da.
W.S. schrieb:
> hmm in meinem Inneren grummelt die Frage, ob die jungen
> Leute heutzutage etwas gelehrt bekommen, den Sinn verstanden und es
> somit gelernt haben oder ob sie lediglich dressiert bzw. abgerichtet
> werden.
Das wird bei dir wie bei mir nicht anders gewesen sein: man bekommt 
nicht alles breit erklärt oder häppchenweise vorgekaut. Wer Interesse an 
seinem Werdegang hat, informiert sich eigenständig und versucht nicht 
nur auswendig zu lernen, sondern eben zu verstehen. Wer diese 
Eigenverantwortung nicht annimmt, ist selbst schuld.
Mein Arbeitsplatz fühlt sich nach so einem Thread immer ein bisschen 
sicherer an :)
OP
Michael H. schrieb:
> Minty Mint schrieb:
>> Letztendlich brauche ich für verschiedene Anwendungsfälle verschiedenen
>> Code.
> und dann stellt sich halt die frage: kannst du die fälle erst zur
> laufzeit oder schon zur compilezeit unterscheiden?

die fälle sind schon zur compilezeit klar.


>> Die Frage ist dann: Wird bei normalem "if" auch sicher nur der nötige
>> Code übersetzt oder nicht?
> grundsätzlich: ja, wird mitübersetzt.

das ist eine etwas widersprüchliche antwort. das "ja" sagt, es wird nur 
der nötige Code übersetzt, das "wird mitübersetzt" sagt, dass der 
unnötige Rest auch übersetzt wird.
wie nun?
Minty Mint schrieb:
> das ist eine etwas widersprüchliche antwort.
Stimmt, entschuldigung!
Was du hinschreibst, wird übersetzt, außer der Compiler kann sicher 
feststellen, dass das Conditional nur einen Zustand einnimmt. Dann 
kann es sein, dass der Compiler optimiert.
z.B.:
1
const int festwert = 10;
2
if(festwert < 5)
3
  a();
4
else
5
  b();
Wenn er aber nicht weiß, was mit Variable passieren kann, wird er beide 
Fälle und das if dazu übersetzen.
Dass muss aber keineswegs immer so sein. Was dein Compiler genau macht, 
musst du nachlesen oder ausprobieren.
Minty Mint schrieb:
> wie nun?

Also wenn du bis hier noch nicht den Unterschied zwischen Präprozessor 
und Compiler mitbekommen hast, würde ich es dir nicht vorwerfen.

Aber daß du trotzdem bis jetzt immer noch nicht selbst angefangen hast 
dich schlau zu machen, z.B. mit einem Buch, zeigt deutlich, daß es 
einfach sinnlos ist dir hier alles vorzukauen.

Was es mit #if auf sich hat, ist erstens elementar für die 
C-Programmierung, und zweitens genau deshalb in jedem C-Buch 
beschrieben.

Wieso sollen die Leute sich hier mehr Mühe geben als du selbst - für 
deine Interessen?

Und wie willst du weitermachen mit Programmieren? Bei jedem Pups hier 
fragen und alles erklären lassen?

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.