Eu quero criar uma macro C que cria uma função com um nome baseado no número da linha. Achei que poderia fazer algo como (a função real teria declarações entre colchetes):
#define UNIQUE static void Unique_##__LINE__(void) {}
Que eu esperava que se expandisse para algo como:
static void Unique_23(void) {}
Isso não funciona. Com a concatenação de token, as macros de posicionamento são tratadas literalmente, acabando por se expandir para:
static void Unique___LINE__(void) {}
Isso é possível fazer?
(Sim, há um motivo real pelo qual quero fazer isso, não importa o quão inútil pareça).
c
macros
concatenation
token
DD.
fonte
fonte
__LINE__
(embora esse seja um caso de uso comum.Respostas:
O problema é que, quando você tem uma substituição de macro, o pré-processador só irá expandir as macros recursivamente se nem o operador de stringizing
#
nem o operador de colagem de token##
forem aplicados a ela. Então, você tem que usar algumas camadas extras de indireção, você pode usar o operador token-colando com um argumento expandido recursivamente:Então,
__LINE__
é expandido para o número da linha durante a expansão deUNIQUE
(uma vez que não está envolvido com#
ou##
), e então a colagem do token acontece durante a expansão deTOKENPASTE
.Também deve ser observado que existe também a
__COUNTER__
macro, que se expande para um novo número inteiro a cada vez que é avaliada, caso seja necessário ter várias instanciações daUNIQUE
macro na mesma linha. Observação:__COUNTER__
é compatível com MS Visual Studio, GCC (desde V4.3) e Clang, mas não é o padrão C.fonte
__COUNTER__
macro não funcionou para mim no gcc; embora__LINE__
um tenha funcionado como anunciado.O GCC não requer "empacotamento" (ou realização) a menos que o resultado precise ser "sequenciado". Gcc tem recursos, mas TUDO pode ser feito com C versão 1 simples (e alguns argumentam que Berkeley 4.3 C é muito mais rápido que vale a pena aprender como usá-lo).
** Clang (llvm) NÃO FAZ ESPAÇO EM BRANCO CORRETAMENTE para expansão de macro - ele adiciona espaços em branco (o que certamente destrói o resultado como sendo um identificador C para pré-processamento posterior) **, clang simplesmente não faz # ou * expansão de macro como um pré-processador C é esperado por décadas. O exemplo principal é a compilação do X11, a macro "Concat3" está quebrada, seu resultado agora é o Identificador C MISNAMED, que obviamente falha na construção. e estou começando a achar que as falhas de build são a profissão deles.
Acho que a resposta aqui é "novo C que quebra os padrões é C ruim", esses hacks sempre optam por (desmontar os namespaces), eles mudam os padrões sem motivo, mas não "melhoram o C" (exceto os seus próprios, digamos: que i digamos que é uma engenhoca feita para explicar por que eles escapam com toda a quebra que ninguém ainda os responsabilizou).
Não é um problema que os pré-processadores C anteriores não suportavam UNIq_ () __ porque eles suportavam #pragma que permite "hackeamento de marca do compilador no código ser sinalizado como hackeamento" e também funcionam tão bem SEM afetar os padrões: defaults é uma quebra de wonton inútil, e assim como alterar o que uma função faz enquanto usa o mesmo nome (namespace clobbering) é ... malware na minha opinião
fonte