2016-01-13 12 views
14

Rozważmy (tylko do odczytu stron trzecich) header lib.h z:Jak zmienić nazwę makra preprocesora C?

#define XYZ 42 

W pliku źródłowym, chcę używać słowa XYZ dla niepowiązanych celu, i nie chcą podstawienie z 42. Ale w tym samym pliku źródłowym, dla innych celów, również chcę uzyskać dostęp do wartości 42 z lib.h bez jej kodowania. Jak zmienić nazwę na z XYZ na, powiedzmy, LIB_XYZ?

Następujące nie działa, ponieważ preprocesor chce XYZ w momencie podstawienia LIB_XYZ jest wykonany, ale XYZ została zdefiniowana:

#include "lib.h" 
#define LIB_XYZ XYZ 
#undef XYZ 

Czy istnieje sposób, aby oszukać preprocesor do rozszerzania LIB_XYZ do jego ostateczna wartość przed utratą XYZ?

+2

Myślę, że utknąłeś, jeśli chcesz uzyskać definicję LIB_XYZ z pliku nagłówkowego strony trzeciej i nie chcesz używać niczego poza kompilatorem C. Gdybym musiał to zrobić, prawdopodobnie napiszę skrypt, by przekształcić lib.h w our_lib.h, z wybranymi # define's modified, make my code include our_lib.h, i użyj makefile, aby uczynić właściwą rzecz, jeśli lib .h zmieniony. –

+1

Być może [this] (http://stackoverflow.com/questions/1793800/can-i-redefine-a---chem-then-define-it-back) może pomóc. –

Odpowiedz

6

Nie z pre-procesorem, przynajmniej nie o tym wiem.

Jednak w przypadku prostych stałych o znanym typie, jak w twoim przykładzie, istnieje obejście.

#include <stdio.h> 

// <xyz.h> 

#define XYZ 42 

// </xyz.h> 

enum xyz_constants 
{ 
    LIB_XYZ = XYZ, 
}; 

#undef XYZ 

#define XYZ 27 

int 
main() 
{ 
    printf("old value: %d, new value: %d\n", LIB_XYZ, XYZ); 
    return 0; 
} 

nie pokazano puch z stdio.h kod ten jest wstępnie przetwarzany w celu poniżej.

enum xyz_constants 
{ 
    LIB_XYZ = 42, 
}; 

int 
main() 
{ 
    printf("old value: %d, new value: %d\n", LIB_XYZ, 27); 
    return 0; 
} 

Można to rozszerzyć w pewnym stopniu na inne typy danych i pewne makra funkcyjne, ale istnieją oczywiście granice.

W każdym razie, dlaczego potrzebujesz konkretnego identyfikatora XYZ? Nie możesz użyć innej nazwy makra?

+1

Sztuczka enum była genialna! Dziękuję Ci! Re: dlaczego XYZ jest podciągiem innego makra innej firmy, które buduję poprzez konkatenację, a makro konkatenacji ma charakter ogólny (działa dla XYZ lub ABC lub czegoś podobnego), więc utknął w XYZ. – alexei

+0

To rozwiązanie właśnie mnie uratowało :) – MByD

0

Użyj innego pliku .c i przypisz wartość makra do zmiennej globalnej.

4

Jeśli XYZ od lib.h jest liczba [lub stała z różnymi], można użyć enum:

enum { LIB_XYZ = XYZ }; 
#undef XYZ 

Jeśli XYZ jest nie powyższego, trzeba stworzyć (np) myxyz.c że robi nie obejmują lib.h i używać XYZ tam (inne pliki mogą zawierać xyz.h)

Różnica polega na tym, że #define LIB_XYZ XYZ będzie nie być rozwiązane na tej linii, tylko wtedy, gdy używasz go później, jak w:

foo(LIB_XYZ); 

tak, że nie będzie działać, bo już #undef'ed na XYZ mam.

0

Symbol preprocesora to nazwa. Nie ma dyrektywy o preprocesorze, która zmienia samą nazwę, zachowując jej zawartość.Na przykład, biorąc pod uwagę zarówno:

#define FOO 42 

lub

#define FOO(x, y) x ## y (

Nie ma sposobu, aby zdefiniować makro o nazwie BAR, który ma te same treści, bez powtarzania tych definicji. To znaczy, nie ma operacji, takich jak:

#alias BAR FOO // nonexistent fantasy macro-cloning preprocessor directive 

Nor tak:

#rename BAR FOO // like #alias BAR FOO followed by #undef FOO 

Jeśli robimy to:

#define BAR FOO // for the #define FOO 42 case 

nie jest aliasem. Makro BAR jest zdefiniowane w taki sposób, że jego zastępczą sekwencją tokenów jest token FOO, a nie 42. Jeśli makro FOO zniknie, oznacza to, że BAR traci znaczenie.

Zauważ też, że makra preprocesora C nie można rozwinąć do dyrektyw preprocesora, więc następujące podejście również nie zadziała:

// wrong: 
#define MACRO_DEFINER(NAME) \ 
    #define NAME 42 

MACRO_DEFINER(FOO) // hoping for #define FOO 42: no such luck 
MACRO_DEFINER(BAR) // hoping for #define BAR 42: likewise 

Obawiam się, że trzeba podjąć kilka kroków, aby znaleźć alternatywna strategia do dowolnego problemu, który próbujesz rozwiązać. Jeśli utkniesz, stwórz nowe pytanie o rzeczywisty problem.

Zawsze jest generowanie kodu: generowanie C lub C++ w czasie kompilacji. Wtedy możliwe jest wymienianie tekstu lub ekspansja, o jakiej można marzyć, jeśli tylko dostroisz system generowania.