Fråga: #define i C, kombinera värden

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Icecap
Inlägg: 26652
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Fråga: #define i C, kombinera värden

Inlägg av Icecap »

Problem:
Ibland (väldigt ofta) definierar jag hårdvara-pinnar med ett namn och deras port-pinne, detta för att göra skrivning & läsning av programmen enklare. Ett exempel:
#define LED_Red PDR5_P55
#define LED_Green PDR5_P56

"#define" gör ju en rent textmässig utbyte så när jag skriver "LED_Green = false; " blir det ju av kompilerns preprocessor gjort om till "PDR5_P56 = false;".
Så långt allt bra, det är ju verkligt en användbar funktion för läsbarhetens skull.

Men jag skulle vilja gå ett steg längre...

Jag har inte hittat något som skulle göra det men jag skulle vilja att man t.ex. kunde skriva såhär:

Först definierar jag alla hårdvaraanslutningar i t.ex. ett kontaktdon:
....
#define Pin_18 PDR8_P86
#define Pin_18_D DDR8_D86
....
Finns eg. 26 pinnar i detta projekt men jag vill inte tråka ut er.

Sedan definierar jag vad jag använder:
#define Some_Signal Pin_18

Och här kommer grejen: Jag skulle gärna vilja ha ett sätt att automatisk kunde lägga till någon text i förlängning av en #define text. I exemplet ovan skulle jag gärna vilja lägga till:
"Some_Signal" + "_D" vilket i slutändan funktionellt skulle bli till en: #define Some_Signal_D

Detta skulle göra det enkelt att göra enkla och stabila hårdvarumässiga definitioner som enkelt kan flyttas och där skrivfel minskas markant.

Men ta mig tusan om jag har hittat hur man ska göra... så är det någon som kan ge mig tips om hur man gör? Om det nu ens går att göra alls...
Användarvisningsbild
adent
Inlägg: 4247
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

Re: Fråga: #define i C, kombinera värden

Inlägg av adent »

Nu har jag inte tänkt riktigt, men ett macro som utnyttjar concatenation borde kanske gå
att få till snyggt? ett exempel:

http://gcc.gnu.org/onlinedocs/gcc-3.2/c ... ation.html

Det är ##:arna som är magiken, de klistrar ihop argumenten.

MVH: Mikael
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: Fråga: #define i C, kombinera värden

Inlägg av johano »

Det låter som du skulle vilja ha två "nivåer" av preprocessormakron..det gär nog inte utan att bygga en egen preprocessor som tuggar igenom filen innan kompilatorns preprocessor kickar in...

I just fallet med D ovan verkar det vara för att annda en annan pinkonfig vid Debug. Då skulle du istället kunna använfa #ifdef/#else/#endif


#ifdef Debug
#define Some_Pin Pin18D
#else
#define Some_Pin Pin18
#endif

/johan
Användarvisningsbild
Icecap
Inlägg: 26652
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Fråga: #define i C, kombinera värden

Inlägg av Icecap »

adent: Bra! Men tyvärr inte helt i mål..

johano: jepp, det är tydligen just problemet: preprocessorn kör bara ett varv...

Själva sammanfogningen går bra men kompilern gnäller ändå över att 'Some_Signal_D' är odefinierat. Det är inte det men det behövs ytterligare ett varv i preprocessorn för att få det hela att fungera och det ids jag inte lägga energi på.

Och det är inte en fråga om att få endera av Some_Signal eller Some_Signal_D, det är frågan om att skapa Some_Signal_D utifrån Some_Signal's verkliga innehåll. Suffixen _D (eller_Dir) använder jag för att ange riktningsregistret till en port.

Tänk såhär:
* Jag anger att LED_Green finns på en viss pinne i ett kontaktdon, t.ex. Pin_18. Jag har tidigare definierat denna som PDR5_P55. Jag har även definierat Pin_18_D som DDR5_D55, alltså riktningsregistret för den pinne.

Jag önskar alltså att jag kunde definiera LED_Green till Pin_18 varefter det fanns lite "automatiska" #defines som ville ta LED_Green och lägga till _D till <innehållet> i LED_Green (Alltså "Pin_18") och lägga till _D så att slutresultatet ville bli samma som att skriva:
#define LED_Green_D Pin_18_D

Nåväl, i.o.m. att preprocessorn bara kör ett varv är det rimligt dödfött... men jag tacka ändå för hjälpen. Det är ju ändå ett lyxproblem så jag kan nog leva utan denna funktion.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Fråga: #define i C, kombinera värden

Inlägg av sodjan »

Jag vet inte om jag uppfattat behovet korrekt, men är det ungefär detta :

Kod: Markera allt

$ 
$ 
$ type test.c

#include <stdio>

#define  LED_Green      "Pin_18"
#define  LED_Green_D    LED_Green ## "_D"

void main()
{

char *text[20];

text[19] = "\0";

printf("LED_Green   = "); 
*text = LED_Green;
printf(*text); 
printf("\n"); 

printf("LED_Green_D = "); 
*text = LED_Green_D;
printf(*text); 
printf("\n"); 

}
$ cc test
$ link test
$ run test
LED_Green   = Pin_18
LED_Green_D = Pin_18_D
$ 
Användarvisningsbild
Icecap
Inlägg: 26652
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Fråga: #define i C, kombinera värden

Inlägg av Icecap »

Rätt - men ändå fel...

Jag behöver inte texten, jag behöver att stycka ihop beteckningar inför preprocessorn.

Jag vill alltså ha det så att:
#define LED_Green Pin_18

medelst lite magi även utlöser:
#define LED_Green_D Pin_18_D

Dessa exempel är ju simpla och banala men i en del andra sammanhang kan det bli oerhört värdefullt att ha sådan en funktion som kan utföra en del automatiska funktioner som säkerställer korrekt definitioner.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Fråga: #define i C, kombinera värden

Inlägg av sodjan »

OK.
Problemet är att jag inte förstår vad du menar med "automatiskt" och "magi"... :-)

Kan du ge ett kort exempel på hur du skulle vilja skriva koden.

> medelst lite magi även utlöser:
> #define LED_Green_D Pin_18_D

Du menar att du inte ens ska behöva SKRIVA den raden alls !?
Den ska bara finnas där endå ?
Nerre
Inlägg: 27235
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Fråga: #define i C, kombinera värden

Inlägg av Nerre »

Icecap, läste du verkligen exemplet ordentligt?

Efter koden

Kod: Markera allt

#define  LED_Green      "Pin_18"
#define  LED_Green_D    LED_Green ## "_D"
Så kommer LED_Green att vara "Pin_18" och LED_Green_D att vara "Pin_18_D".

Om du nu ska ändra till Pin 17 behöver du bara ändra den första #define, inte den andra.
Användarvisningsbild
Icecap
Inlägg: 26652
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Fråga: #define i C, kombinera värden

Inlägg av Icecap »

Jo, jag vet om detta och det fungerar - fast inte på det vis jag vill ha.

Sodjan: just så, jag vill ange t.ex. 'Pin_18' varefter någon annan #define lägger till fler #define med t.ex. 'Pin_18_D' osv. Jag bekymrar mig bara om en här, kan man göra en, kan man göra fler.

Problemet är att preprocessorn inte kör varv nog, den kommer till slutresultatet men ett steg för sent så att säga.

Om vi antar att jag i en hårdvara definitionsfil har skrivit:
#define Pin_18 PDR5_P54 /* Betyder portregister 4 i port 5 */
#define Pin_18_D DDR5_D54 /* Betyder riktningsregister bit 4 för port 5 */
då kommer preprocessorn att ersätta alla förekomster av "Pin_18" med "PDR5_P54" (rent textmässigt) liksom alla förekomster av "Pin_18_D" blir ersatt av "DDR5_D54".

Om jag sedan skriver:
#define LED_Green Pin_18
kommer preprocessorn att byta alla förekomster av "LED_Green" med (i slutändan) "PDR5_P54".

Det jag söker är att jag kan lägga in några "magiska rader" som lägger till en valfri ändelse, t.ex:
#define LED_Green_Dir LED_Green ## _D

Denna rad GER faktisk resultatet "LED_Green_D" men jag vill att den ska ge "Pin_18_D", alltså använda "innehållet" i LED_Green (="Pin_18") som bas vilket i sin tur ersätts med DDR5_D54. Preprocessorn går alltså inte varv nog till att klara detta helt enkelt.

Allt är ett försök på att undvika dessa skrivningsfel som är ganska vanliga men ack så svåra att hitta, kan man alltså ange ett värde ett ställe och bygga andra värden beroende på detta kan man undvika många problem.

Och ja, just i detta extremt enkla exempel kan jag ju bara skriva:
#define LED_Green Pin_18
#define LED_Green_D Pin_18_D
men det är ju lite mer knepigt när man kommer upp och har ett 80-tal anslutningar, där kan det ju lätt bli fel. Kunde man istället ha en skrivning som skapar de rätta definitioner från "basen" ville många problem vara undvikna.
Nerre
Inlägg: 27235
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Fråga: #define i C, kombinera värden

Inlägg av Nerre »

Preprocessorn gör väl inte substitutioner inuti substitutioner? Det är väl det som är problemet, inte varven? För LED_Green är ju redan definierad när du kommer till #define LED_Green_Dir LED_Green ## _D
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Fråga: #define i C, kombinera värden

Inlägg av sodjan »

> #define LED_Green_Dir LED_Green ## _D
> Denna rad GER faktisk resultatet "LED_Green_D"

Så var det inte i mitt exempel (om "LED_Green" är definierad till något annat).

Jag har skrivit om koden lite :

Kod: Markera allt

$ 
$ type pin_def.c
#define  Pin_18         "PDR5_P54" 
$ 
$ type test.c

#include <stdio>

#include "pin_def.c"

#define  LED_Green      Pin_18
#define  LED_Green_D    LED_Green ## "_D"

void main()
{

char *text[20];

text[19] = "\0";

printf("Pin_18   = "); 
*text = Pin_18;
printf(*text); 
printf("\n"); 

printf("LED_Green   = "); 
*text = LED_Green;
printf(*text); 
printf("\n"); 

printf("LED_Green_D = "); 
*text = LED_Green_D;
printf(*text); 
printf("\n"); 

}
$ cc test
$ link test
$ run test
Pin_18   = PDR5_P54
LED_Green   = PDR5_P54
LED_Green_D = PDR5_P54_D
$ 
Är det så du menar ?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Fråga: #define i C, kombinera värden

Inlägg av sodjan »

Nerre> Preprocessorn gör väl inte substitutioner inuti substitutioner?

Menar du så som nedan ?

Kod: Markera allt

$ 
$ typ def_test.c

#include <stdio>

#define  ABC            "XYZ"
#define  ABC2           ABC
#define  ABC3           ABC2
#define  ABC4           ABC3
#define  ABC5           ABC4
#define  ABC6           ABC5

void main()
{

char *text[20];

text[19] = "\0";

printf("ABC6 = "); 
*text = ABC6;
printf(*text); 
printf("\n"); 

}
$ cc def_test.c
$ link def_test
$ run def_test
ABC6 = XYZ
$ 
Eller menar du som en delmängd av en symbol? Då får i jag "undeclared symbol".
Men det fungerar med ## operatorn :

Kod: Markera allt

$ 
$ typ def_test.c

#include <stdio>

#define  ABC            "XYZ"
#define  ABC2           ABC
#define  ABC3           ABC2##"def"

void main()
{

char *text[20];

text[19] = "\0";

printf("ABC3 = "); 
*text = ABC3;
printf(*text); 
printf("\n"); 

}
$ cc def_test
$ link def_test
$ run def_test
ABC3 = XYZdef
$ 
Användarvisningsbild
kimmen
Inlägg: 2042
Blev medlem: 25 augusti 2007, 16:53:51
Ort: Stockholm (Kista)

Re: Fråga: #define i C, kombinera värden

Inlägg av kimmen »

Icecap skrev:Sedan definierar jag vad jag använder:
#define Some_Signal Pin_18

Och här kommer grejen: Jag skulle gärna vilja ha ett sätt att automatisk kunde lägga till någon text i förlängning av en #define text. I exemplet ovan skulle jag gärna vilja lägga till:
"Some_Signal" + "_D" vilket i slutändan funktionellt skulle bli till en: #define Some_Signal_D
Just det går inte att få till, men ett sätt som jag använt är att göra en struct. Vill man ha två lager då kan man ju göra (i headerfil):

Kod: Markera allt

typedef struct
{
  GPIO_TypeDef * port;
  int position;   
} PortInfo;

static const PortInfo PIN18 = { GPIOD, 5 };

#define THE_IMPORTANT_LED PIN18

static inline void setPin(PortInfo pin)
{ // STM32 bit set register
  pin.port->BSRR = 1UL << pin.position;
}

static inline void resetPin(PortInfo pin)
{ // STM32 bit reset register
  pin.port->BRR = 1UL << pin.position;
}

Och då har du ju THE_IMPORTANT_LED.port och THE_IMPORTANT_LED.position som tillsammans kan användas för att göra saker med porten. Det går givetvis att utöka med mer information om det behövs. Deklarerat som static const och med optimering på i GCC blev koden likadan som om jag bara hade gjort konstanter som makron.

En annan möjlighet (som jag först använde) var att deklarera separata static const-variabler med olika namn inifrån ett makro med hjälp av token-pasting-operatorn ##, men det var betydligt fulare och oflexiblare.
Maalobs
Inlägg: 1304
Blev medlem: 3 februari 2005, 14:35:15
Ort: Stockholm

Re: Fråga: #define i C, kombinera värden

Inlägg av Maalobs »

Det är inte tillåtet att göra så här:

Kod: Markera allt

#include <stdio.h>

#define TEST1  "foo"
#define TEST2  "bar"
#define TEST3  TEST1 ## TEST2

void main() {
	char *text[20];
	*text = TEST3;

	printf("TEST3 = %s\n", *text); 
}
Då gnäller kompilatorn på "'TEST1TEST2' : undeclared identifier".

Däremot är det här OK:

Kod: Markera allt

#include <stdio.h>

#define TEST1  "foo"
#define TEST2  "bar"
#define TEST3  TEST1 ## "" ## TEST2

void main() {
	char *text[20];
	*text = TEST3;

	printf("TEST3 = %s\n", *text); 
}
Programmet skriver då ut:
foobar
Användarvisningsbild
Icecap
Inlägg: 26652
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Fråga: #define i C, kombinera värden

Inlägg av Icecap »

Ni verkar väldigt intresserade i att det ska vara textbaserat men PDR5_P54 är en definierat bit i ett definierat register varför jag är otroligt likgiltig i vad som skrivs ut som text, det är en sträng som preprocessorn ska fatta, inget annat.

Jag har insett att det inte går men jag ska kolla lite imorgon, jag har en antydan av en idé jag ska testa då. Jag återkommer med resultatet.
Skriv svar