Hallo zusammen,
ist es möglich #define mitten im code zu definieren.
1
//gewoehnlich ganz oben
2
if(QuelleA)
3
#define register register_a
4
elseif(QuelleB)
5
#define register register_b
6
.
7
.
8
.
je nach dem woher ich meine Daten her kriege (unterschiedliche Quellen)
muss ich unterschiedliche Register ansprechen. Ich weiss aber nicht von
vorn herein welcher Sender (Quelle) mir Daten senden wird. Wollte jetzt
nich unbedingt 10 Funktionen schreiben, eine für jede Quelle, sondern
wenn ich Daten aus der Quelle A habe sollen alle Register der Quelle A
abgearbeitet werden und so weiter...
Prinzipiell kannst das #define hinschreiben, wo du willst - ob es
elegant ist, steht auf einem anderen Blatt.
Das was du vorhast geht aber trotzdem nicht.
Grund: Vor dem eigentlichen Kompilieren läuft der Präprozessor durch die
Datei und kümmert sich u.a. um die #define-Geschichten.
Den interessiert aber dein if nicht, und er weiß auch gar nicht, welcher
Fall zur Laufzeit eintreten wird.
Also sieht er einfach beide #define und wird beim zweiten meckern, weil
es ja schon orher eines mit demselben Namen gab.
(Steht in C-Büchern heute nicht mehr, wie der Präprozessor arbeitet?)
So wie ich Sie verstanden habe Hr. Wachtler, sollte ich dieses vorhaben
sein lassen.
Jut, dann werd ich mal mit dem Schreiben der Funktionen anfangen.
Danke
Gruß
Durchstarter schrieb:> Wollte jetzt nich unbedingt 10 Funktionen schreiben, eine für jede> Quelle, sondern wenn ich Daten aus der Quelle A habe sollen alle> Register der Quelle A abgearbeitet werden und so weiter...
Dann verwende einen Zeiger.
Vorsicht auch mit "elseif" und "register".
Ob diese wörter so erlaubt sind, hängt von der Sprache und dem Compiler
ab...
Wenn ich mich nicht irre, gibts in C kein elseif und "register" könnte
eine Speicherklasse sein ("pack den kram in ein reigster").
Durchstarter schrieb:> So wie ich Sie verstanden habe Hr. Wachtler, sollte ich dieses vorhaben> sein lassen.
ja, so meinte ich das.
Je nachdem, was es genau machen soll, kann in der Tat ein Zeiger das
richtige Mittel sein.
Das könnte etwa so aussehen (angenommen, die Register haben den Typ
register_t):
Kurzschlusselektriker schrieb:> Wenn ich mich nicht irre, gibts in C kein elseif und "register" könnte> eine Speicherklasse sein ("pack den kram in ein reigster").
stimmt, register ist ein reserviertes Schlüsselwort.
undef schrieb:> Natürlich kann man mitten im Code ein #define vereinbaren.
Klar. Nur tut das leider nicht das, was "Durchstarter" sich davon
erwartet hat.
Rolf Magnus schrieb:> Nur tut das leider nicht das, was "Durchstarter" sich davon> erwartet hat.Klaus Wachtler schrieb:> ob es> elegant ist, steht auf einem anderen Blatt.
ich hatte den Satz von KW im Hinterkopf.
Aber auch dann gilt: in den meisten Fällen, wo es verwendet wird, ist
ein #define inzwischen eher kontraproduktiv.
Funktionsähnliche Makros sowieso, aber auch als Konstanten ist eine
const int oder sowas meist sinnvoller.
Ausnahmen gibt es sicher, aber um einen Wert zu definieren sehe ich
eigentlich nur noch zur Übergabe an den Compiler eine Rechtfertigung
(und damit ist es ja auch kein #define, sondern ein -D... :-)
Im RAM? Im ROM? Das entscheidet schlussendlich das Linkerskript. Falls
der Compiler foo_const nicht schon lange wegoptimiert hat.
Habt mal ein bisschen vertrauen in die modernen Compiler, also echt.
Ein const int wird genau dann RAM belegen, wenn es Sinn macht, nämlich
z.B. beim debuggen und keinen, wenn man Optimierungen einschaltet. Da
kann sich jeder gerne im asm-Output (oder debugger) von überzeugen.
Tobi H. schrieb:> Ein const int wird genau dann RAM belegen, wenn es Sinn macht, nämlich> z.B. beim debuggen und keinen, wenn man Optimierungen einschaltet. Da> kann sich jeder gerne im asm-Output (oder debugger) von überzeugen.
Das ist aber Compiler abhängig!
Der eine oder andere Compiler wird die lokale const Variable auf den
Stack legen.
Bartli schrieb:> Und mit solchen Steinzeitcompilern erstellst du täglich Software für> Systeme mit sowenig RAM
Als Entwickler schadet es nicht zu wissen, wie die genutzten Werkzeuge
arbeiten. Das kann der Qualität der Produkte förderlich sein ;-)
Gähn.
Na dann erzähl doch mal, mit was für Compilern du so arbeitest. MSC und
gcc können es ja wohl kaum sein, die sind schon lange nicht mehr so
dämlich.
undef schrieb:> Als Entwickler schadet es nicht zu wissen, wie die genutzten Werkzeuge> arbeiten. Das kann der Qualität der Produkte förderlich sein ;-)
Eben weil es der Qualität nicht förderlich ist, müllt man seinen
Quelltext nicht mehr unnötig mit Makros zu.
Auch das schadet nicht zu wissen.
Abner jeder, wie er will.
Wenn jeder gute SW schreiben würde, wäre ich arbeitslos.
Tobi H. schrieb:> Ein const int wird genau dann RAM belegen, wenn es Sinn macht, nämlich> z.B. beim debuggen und keinen, wenn man Optimierungen einschaltet.
Dann muß er aber auch als static deklariert sein.
Klaus Wachtler schrieb:> Aber auch dann gilt: in den meisten Fällen, wo es verwendet wird, ist> ein #define inzwischen eher kontraproduktiv.> Funktionsähnliche Makros sowieso, aber auch als Konstanten ist eine> const int oder sowas meist sinnvoller.
In C gibt es im Gegensatz zu C++ keine echten Konstanten. Deshalb wird
#define als Ersatz dafür verwendet. Beispiel:
const int arraysize = 5;
int array[arraysize];
das wird außerhalb einer Funktion eine Fehlermeldung geben, da arraysize
eben keine Konstante ist. Oder die oft verwendete Definiton von pi:
1
#define PI (4 *atan(1))
wird als globaler const double auch nicht durch den Compiler gehen. Und
wenn ich in solchen Fällen schon Makros verwende, dann werde ich nicht
so inkonsistent sein und sie in manchen, aber nicht allen Fällen zu
benutzen.
Außerdem kann man selektive Compilierung nur mit Makros machen, genauso
wie z.B. Debug-Funktionen, die Quell-Datei und -Zeile ausgeben oder
sowas wie MAX(), das den größeren von zwei Werten zurückliefert, und
zwar ohne sich dabei auf einen einzelnen Typ einzuschränken. Es gibt
jede Menge Gründe für die Verwendung von Makros in C. In C++ wurden die
meisten davon eliminiert.
Außerdem wird const in C recht "entspannt" gesehen. Es kann auch mal
passieren, daß man die "Konstante" versehentlich ändert, was bei einem
Makro nicht passiert.
Rolf Magnus schrieb:> Dann muß er aber auch als static deklariert sein.
(falls global)
> In C gibt es im Gegensatz zu C++ keine echten Konstanten. Deshalb wird> #define als Ersatz dafür verwendet. Beispiel:>> const int arraysize = 5;> int array[arraysize];
Tja, was ist C?
K&R, ISO-C90: ja
C99: nein, da geht das.
C++ natürlich auch.
> Oder die oft verwendete Definiton von pi:#define PI (4 *atan(1))
Bei dem dummen Compiler von undef wäre das natürlich eine Katastrophe,
der würde jedesmal atan() aufrufen! :-)
> Außerdem kann man selektive Compilierung nur mit Makros machen, genauso> wie z.B. Debug-Funktionen, die Quell-Datei und -Zeile ausgeben
vollkommen richtig; das ist einer der Fälle, die ich pauschal
unterschreibe.
> oder sowas wie MAX(),
ja, wobei man dabei halt schon wieder die Makroprobleme hat (++ bei
Parametern etc.).
> In C++ wurden die> meisten davon eliminiert.
Gott sei es gedankt.
> Außerdem wird const in C recht "entspannt" gesehen. Es kann auch mal> passieren, daß man die "Konstante" versehentlich ändert, was bei einem> Makro nicht passiert.
Oder absichtlich (const volatile...).
----
Ich will auch gar nicht behaupten, daß #define generell böse wäre.
Aber in den meisten Fällen, wo ich eines sehe, ginge es ohne besser.
Ähnlich wie mit goto und anderen Murkserwerkzeugen: man kann es mit
Bedacht verwenden, die meisten machen es anders.
undef schrieb:> Tobi H. schrieb:>> Ein const int wird genau dann RAM belegen, wenn es Sinn macht, nämlich>> z.B. beim debuggen und keinen, wenn man Optimierungen einschaltet. Da>> kann sich jeder gerne im asm-Output (oder debugger) von überzeugen.>> Das ist aber Compiler abhängig!> Der eine oder andere Compiler wird die lokale const Variable auf den> Stack legen.
Und wo kommt sie dann her, diese Konstante und was soll sie auf dem
Stack? Nein du hast leider keine Ahnung oder benutzt Steinzeittools bzw.
kommerziellen Mist.
Durchstarter schrieb:> Hallo zusammen,>> ist es möglich #define mitten im code zu definieren.> //gewoehnlich ganz oben> if (Quelle A)> #define register register_a> elseif(Quelle B)> #define register register_b> .> .> .>> je nach dem woher ich meine Daten her kriege (unterschiedliche Quellen)> muss ich unterschiedliche Register ansprechen. Ich weiss aber nicht von> vorn herein welcher Sender (Quelle) mir Daten senden wird.
Oder mal eine andere Interpretation:
Vielleicht weißt du noch nicht beim Schreiben des Quelltextes, welche
"Quelle" du hast, aber zumindest beim letzlichen Kompilieren (also nicht
erst zur Laufzeit)?
Dann gibt es vielleicht noch etwas in der von dir gewünschten Art:
1
// heute kompilieren wir mit RS232, morgen mit CAN, übermorgen mache
2
// ich der Königin ein Kind...
3
#define QUELLE_IST_RS232
4
//#define QUELLE_IST_CAN
5
//#define QUELLE_IST_KOENIGIN
6
7
#ifdef QUELLE_IST_RS232
8
#define REGISTER (register_a)
9
#elif defined QUELLE_IST_CAN
10
#define REGISTER (register_b)
11
#elif ... etc.
12
#endif
13
14
...
Anstatt des ersten #define QUELLE... könnte man den Compiler dann auch
z.B.mit -DQUELLE_IST_RS232 aufrufen und so mal die eine und mal die
andere Version kompilieren.
> Oder die oft verwendete Definiton von pi:#define PI (4 *atan(1))
pi wird z.B. beim gcc als zahl definiert...
> oder sowas wie MAX(),
std::max() sollte nicht langsamer sein und genauso allgemeingültig (c++
vorausgesetzt). ganz ohne parameter-probleme
> Anstatt des ersten #define QUELLE... könnte man den Compiler dann auch> z.B.mit -DQUELLE_IST_RS232 aufrufen und so mal die eine und mal die> andere Version kompilieren.
Klar, bedingte Kompolierung bezweifelt niemand. Aber warum zwischen den
Blöcken nicht ein
1
constintREGISTER=register_a;
schreiben? Schon sind die defines auf das nötigste reduziert.
Gottseidank wird der neue c++-Standard noch mehr Einsatzzwecke
ausräumen, dann bleibt absolut nur noch die bedingte Kompilierung
Und das kann dann an mehreren Stellen verwendet werden wie zB
gas/config/tc-avr.c
1
#define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \
2
{#NAME, CONSTR, OPCODE, SIZE, ISA, BIN},
3
4
struct avr_opcodes_s avr_opcodes[] =
5
{
6
#include "opcode/avr.h"
7
{NULL, NULL, NULL, 0, 0, 0}
8
};
9
10
#undef AVR_INSN
Ähnliche Konstrukte gibt's in avr-gcc. Eine Struktur anzulegen und
darauf zuzugreifen ist hier nicht unbedingt zielführend, da etwa auch
opt-Dateien, welche gültige Komandozeilen-optionen wie -mmcu= enthalten
und nicht in C-Syntax sind, dadurch abgebildet werden können.
Tobi H. schrieb:> Klar, bedingte Kompolierung bezweifelt niemand. Aber warum zwischen den> Blöcken nicht ein> const int REGISTER = register_a;> schreiben?
Weil das in dem Zusammenhang dann völliger Schwachsinn ist.
Wenn schon, dann:
Bartli schrieb:> Na dann erzähl doch mal, mit was für Compilern du so arbeitest. MSC und> gcc können es ja wohl kaum sein, die sind schon lange nicht mehr so> dämlich.Klaus Wachtler schrieb:> Bei dem dummen Compiler von undefGutdurch schrieb:> Und wo kommt sie dann her, diese Konstante und was soll sie auf dem> Stack? Nein du hast leider keine Ahnung oder benutzt Steinzeittools bzw.> kommerziellen Mist.
Solchen sachlichen und wissenschaftlich fundierten Argumenten kann man
ja nichts mehr entgegnen. ;-P
Da ich aber gerade ein jungfräuliches Visual C++ (2010) unter die Finger
bekam, konnte ich mich dem Beweis eures übermächtigen Wissens nicht
entziehen:
1
#include"stdafx.h"
2
3
4
voidfoo_func(void)
5
{
6
constinti=0x0F0F;
7
8
for(intn=0;n<i;n++)
9
{
10
n++;
11
n--;
12
}
13
}
ergibt
1
;COMDAT?foo_func@@YAXXZ
2
_TEXTSEGMENT
3
_n$5259=-20;size=4
4
_i$=-8;size=4
5
?foo_func@@YAXXZPROC;foo_func,COMDAT
6
;Line5
7
pushebp
8
movebp,esp
9
subesp,216;000000d8H
10
pushebx
11
pushesi
12
pushedi
13
leaedi,DWORDPTR[ebp-216]
14
movecx,54;00000036H
15
moveax,-858993460;ccccccccH
16
repstosd
17
;Line6
18
movDWORDPTR_i$[ebp],3855;00000f0fH
19
;Line8
20
movDWORDPTR_n$5259[ebp],0
21
jmpSHORT$LN3@foo_func
22
$LN2@foo_func:
23
moveax,DWORDPTR_n$5259[ebp]
24
addeax,1
25
movDWORDPTR_n$5259[ebp],eax
26
$LN3@foo_func:
27
cmpDWORDPTR_n$5259[ebp],3855;00000f0fH
28
jgeSHORT$LN4@foo_func
29
;Line10
30
moveax,DWORDPTR_n$5259[ebp]
31
addeax,1
32
movDWORDPTR_n$5259[ebp],eax
33
;Line11
34
moveax,DWORDPTR_n$5259[ebp]
35
subeax,1
36
movDWORDPTR_n$5259[ebp],eax
37
;Line12
38
jmpSHORT$LN2@foo_func
39
$LN4@foo_func:
40
;Line13
41
popedi
42
popesi
43
popebx
44
movesp,ebp
45
popebp
46
ret0
47
?foo_func@@YAXXZENDP;foo_func
48
_TEXTENDS
und
1
#include"stdafx.h"
2
3
4
voidfoo_func(void)
5
{
6
#define i 0x0F0F
7
8
for(intn=0;n<i;n++)
9
{
10
n++;
11
n--;
12
}
13
14
#undef i
15
}
ergibt
1
;COMDAT?foo_func@@YAXXZ
2
_TEXTSEGMENT
3
_n$5258=-8;size=4
4
?foo_func@@YAXXZPROC;foo_func,COMDAT
5
;Line5
6
pushebp
7
movebp,esp
8
subesp,204;000000ccH
9
pushebx
10
pushesi
11
pushedi
12
leaedi,DWORDPTR[ebp-204]
13
movecx,51;00000033H
14
moveax,-858993460;ccccccccH
15
repstosd
16
;Line8
17
movDWORDPTR_n$5258[ebp],0
18
jmpSHORT$LN3@foo_func
19
$LN2@foo_func:
20
moveax,DWORDPTR_n$5258[ebp]
21
addeax,1
22
movDWORDPTR_n$5258[ebp],eax
23
$LN3@foo_func:
24
cmpDWORDPTR_n$5258[ebp],3855;00000f0fH
25
jgeSHORT$LN4@foo_func
26
;Line10
27
moveax,DWORDPTR_n$5258[ebp]
28
addeax,1
29
movDWORDPTR_n$5258[ebp],eax
30
;Line11
31
moveax,DWORDPTR_n$5258[ebp]
32
subeax,1
33
movDWORDPTR_n$5258[ebp],eax
34
;Line12
35
jmpSHORT$LN2@foo_func
36
$LN4@foo_func:
37
;Line15
38
popedi
39
popesi
40
popebx
41
movesp,ebp
42
popebp
43
ret0
44
?foo_func@@YAXXZENDP;foo_func
45
_TEXTENDS
uuuuuupppsss, da fehlt ja der asm Code für die Line 6. Was macht der
wohl im 'const' Beispiel?
> Du hast aber nicht zufällig einen Debug-Build kompiliert?
Natürlich ist das ein Debug-Build. Sieht man ja schon daran, wie immer
schön brav alle Variablen in den Speicher zurückgschrieben werden.
Mein VS2008 optimiert im Release-Build foo_func komplett weg.
> Solchen sachlichen und wissenschaftlich fundierten Argumenten kann man> ja nichts mehr entgegnen. ;-P
Scherzkeks. Dein Beweis oben ist ja sowas von wissenschaftlich.
Klaus Wachtler schrieb:>> In C gibt es im Gegensatz zu C++ keine echten Konstanten. Deshalb wird>> #define als Ersatz dafür verwendet. Beispiel:>>>> const int arraysize = 5;>> int array[arraysize];>> Tja, was ist C?
Offiziell gibt es nur eins, nämlich C99. Deswegen ist das für mich immer
die Referenz.
> K&R, ISO-C90: ja> C99: nein, da geht das.
nein, tut es nicht. Wenn ich die obigen beiden Zeilen in eine Datei
schreibe, meint gcc -std=c99 dazu zurecht:
1
klaus.c:2:5: error: variably modified ‘array’ at file scope
man beachte meinen von dir geschickterweise nicht mitzitierten Satz "das
wird außerhalb einer Funktion eine Fehlermeldung geben". Wenn das
Array lokal und nicht statisch ist, ist das natürlich was anderes, aber
nur weil C99 für diesen Fall die Möglichkeit bietet, auch nichtkonstante
Arraygrößen anzugeben.
> C++ natürlich auch.
Da geht es, weil arraysize in C++ eine echte Konstante ist, und nicht
nur eine Variable mit der Bitte, sie nicht zu beschreiben.
>> Oder die oft verwendete Definiton von pi:#define PI (4 *atan(1))>> Bei dem dummen Compiler von undef wäre das natürlich eine Katastrophe,> der würde jedesmal atan() aufrufen! :-)
Zum Glück nutze ich solche Compiler nicht.
Tobi H. schrieb:>> Oder die oft verwendete Definiton von pi:#define PI (4 *atan(1))> pi wird z.B. beim gcc als zahl definiert...
Beim gcc wird pi gar nicht definiert. Höchstens die von dir verwendete
libc tut das, und wenn sie es in math.h tut, ist das auch noch ein
Verstoß gegen die ISO-Norm.
>> oder sowas wie MAX(),> std::max() sollte nicht langsamer sein und genauso allgemeingültig (c++> vorausgesetzt).
Es geht aber nicht um C++.
Klaus Wachtler schrieb:> Rolf Magnus schrieb:>> Oder die oft verwendete Definiton von pi:#define PI (4 *atan(1))>> Bei dem dummen Compiler von undef wäre das natürlich eine Katastrophe,> der würde jedesmal atan() aufrufen! :-)
Das Ergebnis ist doch vom eingestellten Rounding-Mode abhängig?
Bartli schrieb:> Mein VS2008 optimiert im Release-Build foo_func komplett weg.
Mensch Bartli, du hast es immer noch nicht verstanden: const <irgendwas>
ist für den Compiler eine Variabl. #define USW sieht er nicht, da der
Präprozessor den Text ersetzt. Es spielt doch keine Rolle, ob hinterher
optimiert wird oder nicht.
Das ist wie in der Schule bei Mathe: Wenn dun das richtige Ergebnis vom
Nachbarn abschreibst, hast du aber den Rechenweg nicht verstanden. Was
machst du mal ohne Tischnachbarn?
Für mich ist das Thema jetzt abgeschlossen.
> Mensch Bartli, du hast es immer noch nicht verstanden.
Na dann ist ja gut und deine Welt wieder in Ordnung.
> Als Entwickler schadet es nicht zu wissen, wie die genutzten Werkzeuge> arbeiten. Das kann der Qualität der Produkte förderlich sein ;-)
Genau. Einfach mal ausprobieren: Release-Build deiner Saftware bauen und
staunen wie schnell das plötzlich alles läuft. Du bist ja echt ein
Spassvogel.