Forum: Mikrocontroller und Digitale Elektronik Schwierigkeiten mit c macros


von macro (Gast)


Lesenswert?

Hallo.


Gibt es die Möglichkeit, den Wert einer Variablen mittels macro in einen 
string zu konvertieren? Das ganze sollte so aussehen:


#define MAC(x)  #x


char var = "B";
char B;

 MAC(var) = 3;  <--  hier sollte dann stehen:  B = 3;



Bitte um Hilfe. :)

von Dominik S. (dasd)


Lesenswert?

???
Was soll das bringen?

von Sebastian W. (sebastian_w29)


Lesenswert?

macro schrieb:
> #define MAC(x)  #x
>
> char var = "B";
> char B;
>
>  MAC(var) = 3;  <--  hier sollte dann stehen:  B = 3;

#x (stringify) in einem Makro verwandelt x in einen String. MAC(var) = 
3; wird also zu "var" = 3;

Was du möchtest geht nicht, weil der Preprozessor den Inhalt von 
Variablen nicht kennt.

LG, Sebastian

von macro (Gast)


Lesenswert?

Sebastian W. schrieb:
> Was du möchtest geht nicht, weil der Preprozessor den Inhalt von
> Variablen nicht kennt.

Vielen dank Sebastian für die Info. :)


Gibt es sonst eine Möglichkeit, so etwas zu machen wenn auch nicht mit 
defines? Ich möchte, dass der Benutzer in einem vorgegebenen Datei 
einfach schreiben kann:

  Init.Port = "A";
  Init.Pin  = "A5";

und ich dann an diversen Stellen in meinem Program einfügen kann:

  DDR + Init.Port |= (1<<Init.Pin); <-- also das soll dann bedeuten DDRA 
|= (1<<A5);


Wie macht man sowas? :)

von lange weg (Gast)


Lesenswert?

du schreibst dir ein programm welches dann aus der config datei aus 
Init.Port = "A" ein #define INIT_PORT A macht und in code wird nicht 
Init.Port sondernINIT_PORT verwendet...

das programm wird im make prozess mit eingebunden und wird für dem 
compile porzess ausgeführt

So etwas "ähnliches" machen wir hier, da die debugg messages im Code 
nicht ins Flash gehen werden diese mit ID's versehene. Vorm Compilieren 
werden alle Texte in einer Datenbank hinterlegt mit einer ID und das 
Programm fügt im Text Macro die ID ein wenn noch nicht vergeben. und 
dann wird kompilert. für die Betrachtung auf der Konsole braucht man 
natürlich eine eigene Konsole die die IDs wieder in Strings verwandelt.

Grüße

von XTALE (Gast)


Lesenswert?

lange weg schrieb:
> du schreibst dir ein programm welches dann aus der config datei aus
> Init.Port = "A" ein #define INIT_PORT A macht

Hmm. Wie würde das konkret aussehen? So vll.:
1
switch (Init.Port)
2
{
3
    catch A:
4
         #define INIT_PORT  A
5
    break;
6
    ...
7
}

von Oliver (Gast)


Lesenswert?

In den Anwender-Parameter-header kommt das hier:
1
#define INITPORT A
2
#define INITPIN 5

In deinen header dann das hier:
1
#define CONCAT2(a,b) a##b
2
#define CONCAT(a,b) CONCAT2(a,b)
3
4
#define INIT_PORT CONCAT(PORT, INITPORT)
5
#define INIT_DDR CONCAT(DDR, INITPORT)
6
#define INIT_PIN_PRE CONCAT(P, INITPORT)
7
#define INIT_PIN CONCAT(INIT_PIN_PRE, INITPIN)

Da PAx, PINx, PBx, usw. bei allen bekannten AVRs immer gleich x sind, 
braucht es INIT_PIN eigentlich nicht, da kann man gleich INITPIN 
verwenden.

Also so:
1
 INIT_DDR |= (1<<INIT_PIN);

oder gleich so:
1
 INIT_DDR |= (1<<INITPIN);

Oliver

von Oliver (Gast)


Lesenswert?

Nachtrag:

INITPIN als Bezeichner für die Pinnummer ist in meinem obigen Beispiel 
blöd gewählt, da du ja auch noch das PIN-Register des Ports ansprechen 
können wollen willst ;)

Ber das kriegst du schon selber hin.

Oliver

von lange weg (Gast)


Lesenswert?

da wirst einen parser brauchen, nimmst z.b. java mit config files gehts 
rel. simple da brauchst nur über alle drüber iterieren...

von XTALE (Gast)


Lesenswert?

Oliver schrieb:
> #define CONCAT2(a,b) a##b
> #define CONCAT(a,b) CONCAT2(a,b)

Noch eine kurze Frage. Wieso reicht das nicht aus:

#define CONCAT(a,b) a##b

Was ist der Sinn von CONCAT2?



lange weg schrieb:
> da wirst einen parser brauchen, nimmst z.b. java mit config files gehts
> rel. simple da brauchst nur über alle drüber iterieren...

Hm oki. Danke :)

von Stefan R. (srand)


Lesenswert?

XTALE schrieb:
> Noch eine kurze Frage. Wieso reicht das nicht aus:
>
> #define CONCAT(a,b) a##b
>
> Was ist der Sinn von CONCAT2?

http://www.c-faq.com/ansi/stringize.html

von macro (Gast)


Lesenswert?

Oliver schrieb:
> #define INITPORT A
> #define INITPIN 5

Gibt es eine Möglichkeit, das ganze ohne defines mittels eines 
Funktionsaufrufs zu machen?
1
Init(int Port, int Pin)
2
{
3
   DDR + Port |=  (1<<Pin);    <--- das soll sein:  DDRA |= ....  
4
   ...
5
6
}


Ich hoffe ihr versteht was ich meine. :)

von W.S. (Gast)


Lesenswert?

macro schrieb:
> Ich hoffe ihr versteht was ich meine.

Nein.

Ansonsten halte ich es mit Leuten, die sich im Konstruieren von Macros 
ergehen, so ähnlich wie Osmin: Erst geköpft und dann gehangen, dann 
gespießt auf heiße Stangen, dann..... naja.

Kurzum, Macros sind ein elendiger Mist, den man besser bleiben lassen 
sollte. Wer auf solche Ideen kommt, täte besser daran, seine Algorithmen 
gründlich zu überdenken.

W.S.

von macro (Gast)


Lesenswert?

W.S. schrieb:
> Kurzum, Macros sind ein elendiger Mist, den man besser bleiben lassen
> sollte.

Hi W.S. Deshalb auch meine Frage, ob man macros umgehen kann und vom 
user ausgewählte Ports und pins in Init.Port und Init.Pin ablegen kann. 
Und zwar so ablegen, dass man an vielen Stellen im Quellcode mit DDRx, 
PORTx usw. ansprechen kann.  "Lange weg" hat zwar eine Möglichkeit 
aufgezeigt, aber vielleicht gibt es da auch was einfacheres.


gruß
macro

von Sebastian W. (sebastian_w29)


Lesenswert?

macro schrieb:
> Gibt es eine Möglichkeit, das ganze ohne defines mittels eines
> Funktionsaufrufs zu machen?
>
>
1
> Init(int Port, int Pin)
2
> {
3
>    DDR + Port |=  (1<<Pin);    <--- das soll sein:  DDRA |= ....
4
>    ...
5
> 
6
> }
7
>

Das ginge zur Laufzeit vielleicht so (ist aber nicht genau so effizient 
wie eine Definition zur Compilezeit):
1
volatile uint8_t* WhichIo (char* ioname) {
2
    if (!strcmp(ioname,"DDRA")) return &DDRA;
3
    else if (!strcmp(ioname,"DDRB")) return &DDRB;
4
    else if (!strcmp(ioname,"PORTA")) return &PORTA;
5
    else if (!strcmp(ioname,"PORTB")) return &PORTB;
6
    ...
7
    else return 0;
8
}
9
10
void Init (volatile uint8_t* Ddr, int Pin) {
11
    *Ddr |= 1<<Pin;
12
}
13
14
void ExplicitExample () {
15
    Init(WhichIo("DDRA"),5);
16
    volatile uint8_t* port = WhichIo("PORTA");
17
    *port |= 1<<5;
18
    *port &= ~(1<<5);
19
}
20
21
void ConfigExample () {
22
    char* portname = ReadConfigString("OUTPUTPORT");
23
    char* ddrname = ReadConfigString("OUTPUTDDR");
24
    volatile uint8_t* port = WhichIo(portname);
25
    int pin = ReadConfigInt("OUTPUTPIN");
26
    Init(WhichIo(ddrname),pin);
27
    *port |= 1<<pin;
28
    *port &= ~(1<<pin);
29
}

LG, Sebastian

von W.S. (Gast)


Lesenswert?

macro schrieb:
> und vom
> user ausgewählte Ports und pins in

Hehe.. der User bist doch du selber!
Ich halte es für keine gute Idee, immerzu zwischen "User" und "Ich hier" 
unterscheiden zu wollen. Ich weiß zwar nicht, was du im konkreten Falle 
mit diesem Init.Port usw. bezwecken willst, aber so etwas überhaupt 
anzudenken, ist wirklich falsch. Bedenke doch bitte, daß ein µC immer in 
eine bestimmte Schaltung eingelötet wird und daß er deshalb 
selbstverständlich gerade an seinen Portpins genau so programmiert 
werden muß, wie es die umgebende Schaltung erfordert. Oder willst du 
gelegentlich gegeneinander ankämpfende Output-Pins erzeugen?

Also, schreib dir die Treiberroutinen einfach so, wie es die benutzte 
Peripherie erfordert und halte die zugehörige Headerdatei frei von 
triberinternem Zeugs. Dort sollten nur die Nutzaufrufe stehen, die man 
vom Rest der Firmware aus benötigt, um über den Treiber mit der Hardware 
und damit mit der Außenwelt zu kommunizieren. Dazu braucht man keine 
Macros.

W.S.

von Harry L. (mysth)


Lesenswert?

W.S. schrieb:
> macro schrieb:
>> Ich hoffe ihr versteht was ich meine.
>
> Nein.
>
> Ansonsten halte ich es mit Leuten, die sich im Konstruieren von Macros
> ergehen, so ähnlich wie Osmin: Erst geköpft und dann gehangen, dann
> gespießt auf heiße Stangen, dann..... naja.
>
> Kurzum, Macros sind ein elendiger Mist, den man besser bleiben lassen
> sollte. Wer auf solche Ideen kommt, täte besser daran, seine Algorithmen
> gründlich zu überdenken.
>
> W.S.

Zitat Dieter Nuhr: "Wer keine Ahnung hat....."

Komisch, daß son Müll immer nur anonym gepostet wird.

Makros sind eine hervorragende Möglichkeit, bestimmte Konstrukte lesbar 
zu halten, und trotzdem das Zielsystem nicht mit unnötigen Berechnungen 
zu belasten.
Ausserdem helfen sie Code portabel zu halten
Wenn du W.S. die Funktion von Makros nicht verstehst, und damit nicht 
umgehen kannst, dann lern es, oder halt die Klappe, aber verbreite nicht 
son Blödsinn, und verunsicher nicht die Leute, die ernsthaft 
programmieren lernen wollen!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.