Você pode aninhar C directivas de pré-processador?
-
06-07-2019 - |
Pergunta
Por exemplo, é o seguinte possíveis:
#define definer(x) #define #x?
Solução
Apesar de sua sintaxe é inválida, a resposta para a sua pergunta é tecnicamente sim.Mas ele só pode ser realizada por desagradável truques que fazem o código ilegível e unmaintainable.
Veja também: http://www.ioccc.org/years.html#1995_vanschnitz e http://www.ioccc.org/years.html#2004_vik2
Outras dicas
Não, você não pode fazer isso.
A libra (#
) O símbolo tem um significado diferente em uma definição. Significa - se isso é um argumento, faça uma string citando.
Você não pode aninhar as diretivas de pré -processador C. Felizmente, quase nunca é necessário. Se você realmente precisa desse tipo de poder, quase certamente estará melhor com outro pré -processador que executa antes de entregar o código ao compilador C. Por exemplo:
sed 's/@CUSTOMER@/J. Random Person/' foo.c.in > foo.c
cc foo.c
Outro truque útil é isolar o truque em um único arquivo de cabeçalho, que é gerado por um programa que você escreve:
./generate-trickery --greet 'J. Random Person' > foo.h
onde foo.h vai parecer algo assim:
#define GREET(x) ("J. Random Person greets you, " #x)
Se você amarrar isso com um Makefile, ou alguma outra automação, será bastante perfeita e não tropeçará muito no seu desenvolvimento.
Não, você não pode fazer isso.
Você pode fazer referência a uma macro de outra, mas não pode definir uma macro de outra.
Se você está tentando criar um segmento de código pré -processador que possa ser chamado várias vezes para executar coisas ligeiramente diferentes, uma (moderadamente horrível) maneira que você pode fazer isso é isolar o código em um único .h
arquivo que você então #include
várias vezes. A ideia é que cada vez que você #include
O arquivo que você está "chamando sua rotina" - você "passa argumentos" por primeiro #define
certas constantes de pré -processador a que o arquivo incluído se refere.
Um lugar onde eu vi que isso é útil é gerar enumerações "inteligentes" que podem converter para/a partir de seus formulários "stringizados" (que são úteis para E/S). Você cria um .h
arquivo contendo por exemplo
ENUMVAL(foo)
ENUMVAL(bar)
ENUMVAL(baz)
e depois depois #include
este arquivo duas vezes: uma vez onde ENUMVAL()
é definido de forma a criar um enum
declaração, e uma vez quando ENUMVAL()
é definido de forma a produzir uma variedade de nomes de cordas. Ao fazer dessa maneira, você não precisa especificar a lista de tokens reais mais de uma vez.
#define definer(x) #define #x?
#x is a stringification of x. You can't #define a string token. (#define "foo".) It has to be an identifier [a-zA-Z0-9_]* token.
You can't nest #define's like that. You can't have a #define in a #define.
You can have #if's inside #if blocks.
#ifdef FOO
#ifdef BAR
...
#else // BAR
...
#endif // BAR
#else // FOO
...
#endif //FOO
You are also somewhat limited as to the expressions you can use in #if macros. But you can sometimes work around that. For example:
/* Use CONCATENATE_4_AGAIN to expand the arguments to CONCATENATE_4 */
#define CONCATENATE_4( a,b,c,d) CONCATENATE_4_AGAIN(a,b,c,d)
#define CONCATENATE_4_AGAIN(a,b,c,d) a ## b ## c ## d
/* Creates a typedef that's legal/illegal depending on EXPRESSION. *
* Note that IDENTIFIER_TEXT is limited to "[a-zA-Z0-9_]*". *
* (This may be replaced by static_assert() in future revisions of C++.) */
#define STATIC_ASSERT( EXPRESSION, IDENTIFIER_TEXT) \
typedef char CONCATENATE_4( static_assert____, IDENTIFIER_TEXT, \
____failed_at_line____, __LINE__ ) \
[ (EXPRESSION) ? 1 : -1 ]
Plus something like:
STATIC_ASSERT( sizeof(int1) == 1, sizeof_int1_equal_1 );
(Yes, I know about #include <stdint.h>. It's just an example.)