#define mitten im code

Gast #2273394
Lesenswert?

Hallo zusammen,

ist es möglich #define mitten im code zu definieren.
1
//gewoehnlich ganz oben
2
if (Quelle A)
3
#define   register register_a
4
elseif(Quelle B)
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...

1
void daten_bearbeiten()
2
{
3
    register.RXREGISTER...
4
}

Danke

Gruß

Dennis
#2273398
Lesenswert?

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?)
Gast #2273409
Lesenswert?

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").
#2273412
Lesenswert?

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):
1
    register_t   *p_welchesregister = NULL;
2
    if( irgendwas )
3
    {
4
        p_welchesregister = &register_a;
5
    }
6
    else if( irgendwasanderes )
7
    {
8
        p_welchesregister = &register_b;
9
    }
10
    else if( irgendwasganzanderes )
11
    {
12
        p_welchesregister = &register_c;
13
    }
14
...
15
    daten_bearbeiten( p_welchesregister );
16
....
17

18
void daten_bearbeiten( register_t *p_register )
19
{
20
    if( p_register!=NULL )
21
    {
22
        p_register->RXREGISTER...
23
    }
24
    else
25
    {
26
        // ganz dummer Fehler!
27
        // Meldung ausgeben, Programm abbrechen,
28
        // ab in die Kirche zum Beichten...
29
        ...
30
    }
31
}
#2274890
Lesenswert?

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... :-)
Gast #2274928
Lesenswert?

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.
Gast #2274962
Lesenswert?

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.
#2275110
Lesenswert?

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.
Gast #2275123
Lesenswert?

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.
#2275145
Lesenswert?

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.
Gast #2275161
Lesenswert?

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.
#2275164
Lesenswert?

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.
Persönliche Seite #2275184
Lesenswert?

> 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
const int REGISTER = 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
Persönliche Seite #2276347
Lesenswert?

#define oder #include im Code können durchaus zweckmässig sein.

Hier ein Beispiel aus den avr-binutils:

opcode/avr.h
1
AVR_INSN (clc,  "",    "1001010010001000", 1, AVR_ISA_1200, 0x9488)
2
AVR_INSN (clh,  "",    "1001010011011000", 1, AVR_ISA_1200, 0x94d8)
3
AVR_INSN (cli,  "",    "1001010011111000", 1, AVR_ISA_1200, 0x94f8)
4
...

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.
Gast #2276433
Lesenswert?

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 undef

Gutdurch 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
void foo_func (void)
5
{
6
  const int i = 0x0F0F;
7

8
  for (int n = 0; n < i; n++)
9
  {
10
    n++;
11
    n--;
12
  }
13
}
ergibt
1
;  COMDAT ?foo_func@@YAXXZ
2
_TEXT  SEGMENT
3
_n$5259 = -20            ; size = 4
4
_i$ = -8            ; size = 4
5
?foo_func@@YAXXZ PROC          ; foo_func, COMDAT
6
; Line 5
7
  push  ebp
8
  mov  ebp, esp
9
  sub  esp, 216        ; 000000d8H
10
  push  ebx
11
  push  esi
12
  push  edi
13
  lea  edi, DWORD PTR [ebp-216]
14
  mov  ecx, 54          ; 00000036H
15
  mov  eax, -858993460        ; ccccccccH
16
  rep stosd
17
; Line 6
18
  mov  DWORD PTR _i$[ebp], 3855    ; 00000f0fH
19
; Line 8
20
  mov  DWORD PTR _n$5259[ebp], 0
21
  jmp  SHORT $LN3@foo_func
22
$LN2@foo_func:
23
  mov  eax, DWORD PTR _n$5259[ebp]
24
  add  eax, 1
25
  mov  DWORD PTR _n$5259[ebp], eax
26
$LN3@foo_func:
27
  cmp  DWORD PTR _n$5259[ebp], 3855    ; 00000f0fH
28
  jge  SHORT $LN4@foo_func
29
; Line 10
30
  mov  eax, DWORD PTR _n$5259[ebp]
31
  add  eax, 1
32
  mov  DWORD PTR _n$5259[ebp], eax
33
; Line 11
34
  mov  eax, DWORD PTR _n$5259[ebp]
35
  sub  eax, 1
36
  mov  DWORD PTR _n$5259[ebp], eax
37
; Line 12
38
  jmp  SHORT $LN2@foo_func
39
$LN4@foo_func:
40
; Line 13
41
  pop  edi
42
  pop  esi
43
  pop  ebx
44
  mov  esp, ebp
45
  pop  ebp
46
  ret  0
47
?foo_func@@YAXXZ ENDP          ; foo_func
48
_TEXT  ENDS

und
1
#include "stdafx.h"
2

3

4
void foo_func (void)
5
{
6
#define i  0x0F0F
7

8
  for (int n = 0; n < i; n++)
9
  {
10
    n++;
11
    n--;
12
  }
13

14
#undef i
15
}
ergibt
1
;  COMDAT ?foo_func@@YAXXZ
2
_TEXT  SEGMENT
3
_n$5258 = -8            ; size = 4
4
?foo_func@@YAXXZ PROC          ; foo_func, COMDAT
5
; Line 5
6
  push  ebp
7
  mov  ebp, esp
8
  sub  esp, 204        ; 000000ccH
9
  push  ebx
10
  push  esi
11
  push  edi
12
  lea  edi, DWORD PTR [ebp-204]
13
  mov  ecx, 51          ; 00000033H
14
  mov  eax, -858993460        ; ccccccccH
15
  rep stosd
16
; Line 8
17
  mov  DWORD PTR _n$5258[ebp], 0
18
  jmp  SHORT $LN3@foo_func
19
$LN2@foo_func:
20
  mov  eax, DWORD PTR _n$5258[ebp]
21
  add  eax, 1
22
  mov  DWORD PTR _n$5258[ebp], eax
23
$LN3@foo_func:
24
  cmp  DWORD PTR _n$5258[ebp], 3855    ; 00000f0fH
25
  jge  SHORT $LN4@foo_func
26
; Line 10
27
  mov  eax, DWORD PTR _n$5258[ebp]
28
  add  eax, 1
29
  mov  DWORD PTR _n$5258[ebp], eax
30
; Line 11
31
  mov  eax, DWORD PTR _n$5258[ebp]
32
  sub  eax, 1
33
  mov  DWORD PTR _n$5258[ebp], eax
34
; Line 12
35
  jmp  SHORT $LN2@foo_func
36
$LN4@foo_func:
37
; Line 15
38
  pop  edi
39
  pop  esi
40
  pop  ebx
41
  mov  esp, ebp
42
  pop  ebp
43
  ret  0
44
?foo_func@@YAXXZ ENDP          ; foo_func
45
_TEXT  ENDS

uuuuuupppsss, da fehlt ja der asm Code für die Line 6. Was macht der 
wohl im 'const' Beispiel?
Gast #2276492
Lesenswert?

> 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.
1
void foo_func (void)
2
{
3
  const int i = 0x0F0F;
4
  int n;
5

6
  for (n = 0; n < i; n++)
7
  {
8
    n++;
9
    n--;
10
  }
11
}
12

13
int main(int argc, char **argv)
14
{
15
  foo_func();
16
}

=>
1
--- c:\users\xxx\desktop\test\test\test.c --------------------------------------
2
void foo_func (void)
3
{
4
  const int i = 0x0F0F;
5
  int n;
6

7
  for (n = 0; n < i; n++)
8
  {
9
    n++;
10
    n--;
11
  }
12
}
13

14
int main(int argc, char **argv)
15
{
16
  foo_func();
17
}
18
00241000  xor         eax,eax 
19
00241002  ret              
20
--- f:\dd\vctools\crt_bld\self_x86\crt\src\intel\secchk.c ----------------------

> Solchen sachlichen und wissenschaftlich fundierten Argumenten kann man
> ja nichts mehr entgegnen. ;-P

Scherzkeks. Dein Beweis oben ist ja sowas von wissenschaftlich.
Gast #2276651
Lesenswert?

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++.
Gast #2277085
Lesenswert?

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.
Gast #2277496
Lesenswert?

> 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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren