Come funziona esattamente il trucco della doppia stringa?


84

Almeno alcuni preprocessori C consentono di stringere il valore di una macro, piuttosto che il suo nome, facendolo passare attraverso una macro simile a una funzione a un'altra che lo stringa:

Esempi di casi d'uso qui .

Questo funziona, almeno in GCC e Clang (entrambi con -std=c99), ma non sono sicuro di come funzioni in termini di standard C.

Questo comportamento è garantito da C99?
In caso affermativo, come lo garantisce C99?
In caso negativo, a che punto il comportamento passa da definito da C a definito da GCC?


1
Se dici "almeno un po '", significa che ne hai visto uno in cui non funziona? Sono disposto a scrivere una segnalazione di bug al venditore.
Jens

@ Jens: No; Non l'ho fatto. Ogni compilatore che ho usato (vale a dire, GCC e Clang) implementa questo comportamento.
Peter Hosey

Risposte:


80

Sì, è garantito.

Funziona perché gli argomenti delle macro sono essi stessi macro-espansi, tranne dove il nome dell'argomento macro appare nel corpo della macro con lo stringifier # o il token-paster ##.

6.10.3.1/1:

... Dopo che gli argomenti per l'invocazione di una macro simile a una funzione sono stati identificati, ha luogo la sostituzione degli argomenti. Un parametro nell'elenco di sostituzione, a meno che non sia preceduto da un token di pre-elaborazione # o ## o seguito da un token di pre-elaborazione ## (vedere sotto), viene sostituito dall'argomento corrispondente dopo che tutte le macro in esso contenute sono state espanse ...

Quindi, se lo fai STR1(THE_ANSWER), ottieni "THE_ANSWER", perché l'argomento di STR1 non è macro espanso. Tuttavia, l'argomento di STR2 è macroespanso quando viene sostituito nella definizione di STR2, che quindi fornisce a STR1 un argomento di 42, con il risultato di "42".


21

Come osserva Steve, questo è garantito, ed è stato garantito dallo standard C89 - quello era lo standard che codificava gli operatori # e ## nelle macro e imponeva l'espansione ricorsiva delle macro in args prima di sostituirle nel corpo se e solo se il corpo non applica un # o un ## all'argomento. C99 è invariato da C89 sotto questo aspetto.


+1 per aver dedicato del tempo per confermare che fa parte anche di C89. Alcuni di noi si preoccupano della portabilità, inclusa la creazione di codice che le persone che compilano in modalità C89 possono utilizzare: solo pochi anni fa le versioni di gcc erano ancora predefinite C89 (più le estensioni gcc per essere onesti), MSVC l'ultima volta che ho sentito supporta ancora solo C89 e incorporato o anche i sistemi legacy a volte hanno solo compilatori C89. C89 rappresenta un "piano terra" di grande portabilità, uno standard minimo comune denominatore che le persone possono scegliere di compilare e gestire per qualsiasi cosa nell'uso pratico oggi. Quindi è molto bello vederlo ricordato.
mtraceur
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.