2010-09-03 14 views
6

Próbuję zdefiniować makro, aby wygenerować nazwę tokena, zawierającą zmienną.C Konformacja makro tokenów ze zmienną - czy to możliwe?

Zasadniczo co próbuję to:

#define GLUER(x,y,z) x##y##z 
#define PxDIR(x) GLUER(P,x,DIR) 

int main() { 
    int port; 
    port = 2; 
    PxDIR(port) |= 0x01; 
} 

Mam nadzieję, że do wygenerowania tokenu P2DIR z powyższego zestawienia, ale zgodnie z moim wyjściu kompilatora, to generowanie tokenu PportDIR, który jest NIE to, czego chciałem. Jakąkolwiek pomoc tutaj? Czy jest to, co próbuję zrobić niemożliwe?

+0

Czy masz zamiar zrobić '#define port 2'? – Gabe

Odpowiedz

6

Nie sądzę, że to, co próbujesz zrobić, jest możliwe. Makra C to naprawdę makra preprocesora, które są rozwijane przed kompilacją. Zmienna port nie zostanie ustawiona do czasu wykonania.

+0

Dzięki, właśnie o tym myślałem. Minęło trochę czasu, odkąd zrobiłem proste C. – gatesphere

3

To niemożliwe. Preprocesory C działają przez przetwarzanie tokenów i nie wykonują żadnej rozdzielczości ani substytucji, które wymagałyby znajomości mechaniki języka (poza podstawową arytmetyką obejmującą literały całkowite, poza moim zasięgiem). Rozważmy na przykład dokumentację dla preprocesora GCC regarding tokenisation. Tylko kompilator będzie wiedział, co zrobić ze zmienną "port".

Jednym rozwiązaniem jest zrobić coś takiego:

#define PxDIR(var, portnum) do { \ 
    var = portnum; \ 
    P##portnum##DIR |= blah; \ 
} while(0) 

... a później ...

int port; 
PxDIR(port, 2); 

zostawiam to do ciebie, aby to nie tak brzydki lub hacky, jak to jest tutaj (i bardziej ogólnie, w zależności od tego, co trzeba) :)

+0

Dzięki. Szukałem go jako sposobu na zredukowanie nadmiaru kodu w projekcie osadzonym, ale wygląda na to, że nie można użyć zmiennej do rozwiązania tego problemu. Ach tak. Dzięki jeszcze raz! – gatesphere

+0

@ user438605 Rzeczywiście - chociaż możesz chcieć spojrzeć na [X Macro Idiom] (http://www.drdobbs.com/184401387) w celu wielokrotnego generowania kodu. – detly

2

... lub po prostu zrobić PORT również makra:

#define PORT 2 
#define GLUER(x,y,z) x##y##z 
#define PxDIR(x) GLUER(P,x,DIR) 

int main() { 
    PxDIR(PORT) |= 0x01; 
    return 0; 
} 
0

To, co próbujesz zrobić, nie ma sensu.

#define GLUER(x,y,z) x##y##z 
#define PxDIR(x) GLUER(P,x,DIR) 

int main() { 
    int port; 
    port = 2; 
    PxDIR(port) |= 0x01; 
} 

Preprocesser jest uruchamiany w (przed) czasie kompilacji. Dlatego nie może nic wiedzieć o zawartości zmiennej port. Preprocesor wymaga, aby wszelkie wartości przekazywane jako argumenty makr były stałe. Na przykład, można wykonać następujące czynności:

#define GLUER(x,y,z) x##y##z 
#define PxDIR(x) GLUER(P,x,DIR) 

int main() { 
    PxDIR(2) |= 0x01; //setup port 2 
} 

W przeciwnym razie, jeśli chcesz być w stanie przekazać zmienną do tego makra naprawdę jedynym sposobem jest, aby upewnić się, że kod, aby to zrobić jest wyraźnie generowane:

#define GLUER(x,y,z) x##y##z 
#define PxDIR(x) GLUER(P,x,DIR) 

uint16_t* get_port_pointer(uint8_t port_id) { 
    if (port == 0) { 
    return &PxDIR(0); 
    } else if (port == 1) { 
    return &PxDIR(1); 
    } else if (port == 2) { 
    return &PxDIR(2); 
    } else if (port == 3) { 
    return &PxDIR(3); 
    } else { 
    return &0; 
    } 
} 

int main() { 
    int port; 
    port = 2; 

    *(get_port_pointer(port)) |= 0x01; 
} 

W ten sposób upewniamy się, że istnieje kod dla dowolnego portu od 0 do 3, aby uzyskać do niego dostęp. Również teraz musimy uważać na wskaźniki null zwracane z funkcji get_port_pointer.