Creazione di macro C con ## e __LINE__ (concatenazione di token con macro di posizionamento)

Voglio creare una macro C che crei una funzione con un nome basato sul numero di riga. Pensavo di poter fare qualcosa di simile (la vera funzione avrebbe delle affermazioni all’interno delle parentesi graffe):

#define UNIQUE static void Unique_##__LINE__(void) {} 

Che speravo si espandesse in qualcosa di simile:

 static void Unique_23(void) {} 

Questo non funziona. Con la concatenazione di token, le macro di posizionamento vengono trattate letteralmente, finendo per espandersi in:

 static void Unique___LINE__(void) {} 

È ansible farlo?

(Sì, c’è una vera ragione per cui voglio farlo, non importa quanto questo sia inutile).

Il problema è che quando si ha una sostituzione di macro, il preprocessore espanderà le macro solo in modo ricorsivo se non viene applicato né l’operatore di #natura né l’operatore ## token-pasting. Quindi, è necessario utilizzare alcuni livelli aggiuntivi di riferimento indiretto, è ansible utilizzare l’operatore di token-pasting con un argomento espanso ricorsivamente:

 #define TOKENPASTE(x, y) x ## y #define TOKENPASTE2(x, y) TOKENPASTE(x, y) #define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {} 

Quindi, __LINE__ viene espanso al numero di riga durante l’espansione di UNIQUE (poiché non è coinvolto né da # né da ## ), e quindi l’incollatura dei token avviene durante l’espansione di TOKENPASTE .

Va anche notato che esiste anche la macro __COUNTER__ , che si espande in un nuovo intero ogni volta che viene valutata, nel caso in cui sia necessario avere più istanze della macro UNIQUE sulla stessa riga. Nota: __COUNTER__ è supportato da MS Visual Studio, GCC (dalla V4.3) e Clang, ma non è standard C.

GCC non richiede “wrapping” (o realizzazione) a meno che il risultato non debba essere “stringificato”. Gcc ha delle caratteristiche ma TUTTO può essere fatto con la semplice versione C 1 (e alcuni sostengono che Berkeley 4.3 C sia molto più veloce che valga la pena imparare a usare).

** Clang (llvm) NON FUNZIONA CORRETTAMENTE SPAZIO BIANCO per l’espansione macro – aggiunge spazio bianco (che sicuramente distrugge il risultato come identificativo C per ulteriori pre-elaborazioni) **, clang semplicemente non fa # o * espansione macro come previsto un preprocessore C per decenni. L’esempio principale è la compilazione di X11, la macro “Concat3” è rotta, il suo risultato è ora MISNAMED C Identifier, che ovviamente non riesce a build. e sto iniziando a build cose che falliscono sono la loro professione.

Penso che la risposta qui sia “nuova C che rompe gli standard è ctriggers C”, questi hack sempre scelgono (clobber namespaces) cambiano i valori predefiniti senza motivo ma in realtà non “migliorano C” (a parte il loro dire così: quale io Diciamo che è un aggeggio fatto per spiegare perché riescono a cavarsela con tutte le rotture che nessuno ha ancora reso responsabili per).


Non è un problema che i precedenti pre-processori C non supportassero UNIq_ () __ perché supportavano #pragma che consente a “hackeraggio del marchio del compilatore nel codice di essere contrassegnato come hacker” e anche di funzionare altrettanto SENZA influenzare gli standard: così come cambiare le impostazioni predefinite sono inutili rottura del wonton, e proprio come cambiando ciò che una funzione fa mentre si utilizza lo stesso nome (clobbering del namespace) è … il malware secondo me