Concatenazione di stringhe macro C / C ++


121
#define STR1      "s"
#define STR2      "1"
#define STR3      STR1 ## STR2

È possibile concatenare have STR3 == "s1"? Puoi farlo passando gli argomenti a un'altra funzione Macro. Ma esiste un modo diretto?


Non dovrebbe essere #define STR3 STR1 ## STR2
Shrinidhi

Non dovrebbe esserlo perché questo definisce STR3 come il token di pre-elaborazione STR1STR2. E il passaggio di argomenti a un'altra funzione macro non aiuta, perché le stringhe letterali non possono essere incollate insieme - "s" "1" non è un token valido.
Jim Balter

Risposte:


157

Se sono entrambe le stringhe puoi semplicemente fare:

#define STR3 STR1 STR2

Il preprocessore concatena automaticamente le stringhe adiacenti.

MODIFICARE:

Come indicato di seguito, non è il preprocessore ma il compilatore che esegue la concatenazione.


17
Tecnicamente, la concatenazione di stringhe viene eseguita a livello di lingua.
Martin York

47
Il preprocessore non fa nulla di simile. È il linguaggio C vero e proprio che tratta i letterali stringa adiacenti come se fossero un singolo letterale stringa.
Jim Balter

7
È più di un tecnicismo: non puoi concatenare L"a"e "b"ottenere L"ab", ma puoi concatenare L"a"e L"b"ottenere L"ab".
MSalters

115

Non hai bisogno di quel tipo di soluzione per i letterali stringa, poiché sono concatenati a livello di linguaggio, e non funzionerebbe comunque perché "s" "1" non è un token preprocessore valido.

[Modifica: in risposta al commento "Solo per la cronaca" errato di seguito che purtroppo ha ricevuto diversi voti positivi, ribadirò l'affermazione sopra e osserverò che il frammento di programma

#define PPCAT_NX(A, B) A ## B
PPCAT_NX("s", "1")

produce questo messaggio di errore dalla fase di pre-elaborazione di gcc: errore: incollare "" s "" e "" 1 "" non fornisce un token di pre-elaborazione valido

]

Tuttavia, per incollare token generali, prova questo:

/*
 * Concatenate preprocessor tokens A and B without expanding macro definitions
 * (however, if invoked from a macro, macro arguments are expanded).
 */
#define PPCAT_NX(A, B) A ## B

/*
 * Concatenate preprocessor tokens A and B after macro-expanding them.
 */
#define PPCAT(A, B) PPCAT_NX(A, B)

Quindi, ad esempio, entrambi PPCAT_NX(s, 1)e PPCAT(s, 1)producono l'identificatore s1, a meno che non ssia definito come macro, nel qual caso PPCAT(s, 1)produce <macro value of s>1.

Continuando sul tema ci sono queste macro:

/*
 * Turn A into a string literal without expanding macro definitions
 * (however, if invoked from a macro, macro arguments are expanded).
 */
#define STRINGIZE_NX(A) #A

/*
 * Turn A into a string literal after macro-expanding it.
 */
#define STRINGIZE(A) STRINGIZE_NX(A)

Poi,

#define T1 s
#define T2 1
STRINGIZE(PPCAT(T1, T2)) // produces "s1"

Al contrario,

STRINGIZE(PPCAT_NX(T1, T2)) // produces "T1T2"
STRINGIZE_NX(PPCAT_NX(T1, T2)) // produces "PPCAT_NX(T1, T2)"

#define T1T2 visit the zoo
STRINGIZE(PPCAT_NX(T1, T2)) // produces "visit the zoo"
STRINGIZE_NX(PPCAT(T1, T2)) // produces "PPCAT(T1, T2)"

8
Solo per la cronaca, "s""1"è valido in C (e C ++). Sono due token (stringhe letterali) che il compilatore potrebbe concatenare e minacciare come un unico token.
Shahbaz

4
Hai frainteso sia il mio commento che il linguaggio C. Ho detto "s""1" isn't a valid token- è corretto; sono, come dici tu, due gettoni. Ma unirli insieme a ## li renderebbe un unico token di pre-elaborazione, non due token, e quindi il compilatore non farebbe una concatenazione, piuttosto il lexer li rifiuterebbe (il linguaggio richiede una diagnostica).
Jim Balter

8
@ mr5 Leggi i commenti, con attenzione. I nomi delle macro passati come argomenti macro non vengono espansi prima di essere passati. Tuttavia, sono espansi nel corpo della macro. Quindi, se A è definito come FRED, STRINGIZE_NX (A) si espande in "A" ma STRINGIZE (A) si espande in STRINGIZE_NX (FRED) che si espande in "FRED".
Jim Balter

1
@bharath la stringa risultante è "PPCAT (T1, T2)" - come previsto e desiderato. e non l'atteso "s1" - per niente previsto. Perché abbiamo bisogno di un'indirizzamento / annidamento extra? - Leggi i commenti sul codice e il mio commento sopra con i 6 voti positivi. Vengono espansi solo i corpi delle macro; al di fuori dei corpi macro, gli argomenti macro tra parentesi non vengono espansi prima di essere passati alle macro. Quindi si STRINGIZE_NX(whatever occurs here)espande a "qualunque cosa accada qui", indipendentemente da qualsiasi definizione di macro per qualunque cosa, accada o qui.
Jim Balter

1
@bharath Ovviamente non stampa "Nome A" - A è il nome del parametro, non l'argomento della macro, che è ALEX. Hai affermato if A is defined as FRED then STRINGIZE_NX(A) still expands to "FRED"che è falso e non ha niente a che fare con il tuo test. Stai cercando di non capire o di non farlo bene, e non ti risponderò ulteriormente.
Jim Balter

24

Suggerimento: la STRINGIZEmacro sopra è interessante, ma se commetti un errore e il suo argomento non è una macro - hai avuto un errore di battitura nel nome o hai dimenticato #includeil file di intestazione - allora il compilatore metterà felicemente il nome della macro presunta nel stringa senza errori.

Se intendi che l'argomento a STRINGIZEsia sempre una macro con un valore C normale, allora

#define STRINGIZE(A) ((A),STRINGIZE_NX(A))

lo espanderà una volta e ne verificherà la validità, lo scarterà e poi lo espanderà di nuovo in una stringa.

Mi ci è voluto un po 'per capire perché STRINGIZE(ENOENT)stava finendo come "ENOENT"invece di "2"... non avevo incluso errno.h.


2
Osservazione importante e +1 per un corretto utilizzo ,dell'operatore. :)
Jesse Chisholm

2
Non c'è motivo particolare per cui il contenuto della stringa dovrebbe essere un'espressione C valida. Se vuoi farlo, ti consiglio di dargli un nome diverso, come STRINGIZE_EXPR.
Jim Balter

Quel trucco potrebbe aver funzionato da solo. Ma impedisce al compilatore di vedere una sequenza di stringhe che concatenerà. (risultante in sequenze come ((1),"1") "." ((2),"2")invece di "1" "." "2")
automorfico

Giusto per chiarire cosa sta dicendo automorfico: con la STRINGIZEdefinizione originale , "The value of ENOENT is " STRINGIZE(ENOENT)funziona, mentre "The value of ENOENT is" STRINGIZE_EXPR(X)produce un errore.
Jim Balter,
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.