2008-11-19 20 views
25

Chciałbym zrobić równowartość co następuje:Czy makra preprocesora C mogą zawierać dyrektywy preprocesora?

#define print_max(TYPE) \ 
# ifdef TYPE##_MAX \ 
    printf("%lld\n", TYPE##_MAX); \ 
# endif 

print_max(INT); 

Teraz #ifdef lub dowolny zagnieżdżone dyrektywy preprocesora jest niedozwolone o ile widzę w funkcji makro. Jakieś pomysły?

Aktualizacja: Wygląda na to, że nie jest to możliwe. Nawet hack do sprawdzenia w czasie wykonywania wydaje się nieosiągalny. Więc myślę, że pójdę z czymś takim:

#ifndef BLAH_MAX 
# define BLAH_MAX 0 
#endif 
# etc... for each type I'm interested in 

#define print_max(TYPE) \ 
    if (TYPE##_MAX) \ 
     printf("%lld\n", TYPE##_MAX); 

print_max(INT); 
print_max(BLAH); 

Odpowiedz

0

Nie sądzę, że jest to sprawa operatora ## nie jest dozwolone w #ifdef. Próbowałem tego:

i nadal nie działało (nie podobało się TYP #ifdef). Problem polega na tym, że #ifdef zaakceptuje tylko # zdefiniowane symbole, a nie argumenty #define. To są dwie różne rzeczy.

4

Próbowałem już wcześniej. Problem polega na tym, że # jest już zarezerwowane dla sznurowania parametru makro. Nie jest analizowany jako znacznik preprocesora, taki jak zdefiniowany w #.

0

W przeciwieństwie do szablonów, preprocesorem nie jest turing-complete. An #ifdef wewnątrz makra nie jest możliwe. Twoim jedynym rozwiązaniem jest upewnienie się, że wywołujesz tylko print_max dla typów, które mają pasujące wartości zdefiniowane, np. _MAX. INT_MAX. Kompilator na pewno powie Ci, kiedy nie są.

2

Jedyne rozwiązanie, jakie mam, to oszustwo - tworzy listę typów, które mają _XXX_MAX jako zestaw definicji, a następnie używają tego. Nie wiem, jak utworzyć listę w sposób automatyczny w preprocesorze, więc nie próbuję. Zakłada się, że lista nie jest zbyt długa i nie będzie utrzymywana zbyt intensywnie.

#define PRINT_MAX(type) printf("%lld\n", _TYPE##_MAX); 
#define HAVE_MAX(type) _TYPE##_MAX // not sure if this works 


/* a repetitious block of code that I cannot factor out - this is the cheat */ 
#ifdef HAVE_MAX(INT) 
#define PRINT_INT_MAX PRINT_MAX(INT) 
#endif 

#ifdef HAVE_MAX(LONG) 
#define PRINT_LONG_MAX PRINT_MAX(LONG) 
#endif 
/* end of cheat */ 


#define print_max(type) PRINT_##TYPE##_MAX 
10

Boost Preprocessor (który pracuje dla C oraz C++, choć doładowania jako całość jest biblioteka C++) biblioteka może pomóc z tego rodzaju zadania. Zamiast używać #ifdef w makrze (co jest niedozwolone), możesz dołączyć plik wiele razy, z różnymi makrami zdefiniowanymi za każdym razem, aby plik mógł używać #ifdef.

Poniższy kod, jeśli zapisano w max.c, powinien zrobić to, co chcesz dla każdego słowa wymienionego w definicji MAXES # u góry pliku. Jednak nie zadziała, jeśli dowolna z wartości _MAX jest zmiennoprzecinkowych, ponieważ preprocesor nie może obsłużyć zmiennoprzecinkowej.

(boost Procesor to poręczne narzędzie, ale to nie jest dokładnie prosta, można zdecydować, czy takie podejście jest lepsze od kopiowania i wklejania.)

#define MAXES (SHRT)(INT)(LONG)(PATH)(DOESNT_EXIST) 

#if !BOOST_PP_IS_ITERATING 

/* This portion of the file (from here to #else) is the "main" file */ 

#include <values.h> 
#include <stdio.h> 
#include <boost/preprocessor.hpp> 

/* Define a function print_maxes that iterates over the bottom portion of this 
* file for each word in MAXES */ 
#define BOOST_PP_FILENAME_1 "max.c" 
#define BOOST_PP_ITERATION_LIMITS (0,BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(MAXES))) 
void print_maxes(void) { 
#include BOOST_PP_ITERATE() 
} 

int main(int argc, char *argv[]) 
{ 
    print_maxes(); 
} 

#else 

/* This portion of the file is evaluated multiple times, with 
* BOOST_PP_ITERATION() resolving to a different number every time */ 

/* Use BOOST_PP_ITERATION() to look up the current word in MAXES */ 
#define CURRENT BOOST_PP_SEQ_ELEM(BOOST_PP_ITERATION(), MAXES) 
#define CURRENT_MAX BOOST_PP_CAT(CURRENT, _MAX) 

#if CURRENT_MAX 
printf("The max of " BOOST_PP_STRINGIZE(CURRENT) " is %lld\n", (long long) CURRENT_MAX); 
#else 
printf("The max of " BOOST_PP_STRINGIZE(CURRENT) " is undefined\n"); 
#endif 

#undef CURRENT 
#undef CURRENT_MAX 

#endif 
0

Nie ma łatwy sposób zrobić to. Najbliższy można przyjść ma #define dużą liczbę ifdef makr, takich jak:

#undef IFDEF_INT_MAX 
#ifdef INT_MAX 
#define IFDEF_INT_MAX(X) X 
#else 
#define IFDEF_INT_MAX(X) 
#endif 

#undef IFDEF_BLAH_MAX 
#ifdef BLAH_MAX 
#define IFDEF_BLAH_MAX(X) X 
#else 
#define IFDEF_BLAH_MAX(X) 
#endif 

    : 

ponieważ trzeba wiele z nich (i mogą być użyteczne wielu miejsc), to sprawia, że ​​wiele sensu, aby przykleić wszystkie te pliki do własnego pliku nagłówkowego "ifdefs.h", który można dołączyć, gdy będzie potrzebny. Możesz nawet napisać skrypt, który odradza ifdef.h od listy „makr zainteresowania”

Następnie kod staje

#include "ifdefs.h" 
#define print_max(TYPE) \ 
IFDEF_##TYPE##_MAX(printf("%lld\n", TYPE##_MAX);) 

print_max(INT); 
print_max(BLAH);