Domanda

Sto lavorando a un progetto in cui ho molte stringhe costanti formate dalla concatenazione (numeri, ecc.).

Ad esempio, ho un file LOCATION macro che formati __FILE__ e __LINE__ in una stringa che posso usare per sapere dove mi trovo nel codice, quando si stampa messaggi o errori:

#define _STR(x)    # x
#define STR(x)     _STR(x)
#define LOCATION __FILE__ "(" STR(__LINE__) ")"

Quindi, questo formatterebbe una posizione come "file.cpp (42)". Il problema è quando provo a convertire il risultato in una corda ampia:

#define _WIDEN(x)  L ## x
#define WIDEN(x)   _WIDEN(x)
#define WLOCATION  WIDEN(LOCATION)

Funziona bene con GCC e si traduce in l "file.cpp (42)" inserito nel mio codice. Tuttavia, quando ci provi con MSVC ++ (usando Visual C ++ 2008 Express), ricevo un errore:

error: Concatenating wide "file.cpp" with narrow "("

Capisco che il L Il prefisso viene aggiunto solo al primo termine nella mia espressione. Ho anche provato questo:

#define _WIDEN(x) L ## #x

Quale "funziona", ma dà la stringa L"\"file.cpp\" \"(\" \"42\" \")\"" Il che ovviamente non è molto conveniente (e non quello che sto cercando), soprattutto considerando che questa macro è semplice rispetto ad altre macro.

Quindi, la mia domanda è: come posso farlo applicare all'intera espressione in MSVC ++, quindi posso ottenere lo stesso risultato che ottengo con GCC? Preferirei non creare una seconda stringa con token a tutto campo, perché dovrei quindi mantenere due macro per ognuna, il che non è molto conveniente e può portare a bug. Inoltre, ho bisogno anche della versione stretta di ogni stringa, quindi l'uso di stringhe a tutto campo non è nemmeno un'opzione, purtroppo.

È stato utile?

Soluzione

Secondo lo standard C (aka "ISO-9899: 1999" aka "C99"), Visual C è sbagliato e GCC è corretto. Quegli stati standard, Sezione 6.4.5/4:

Nella traduzione di Fase 6, le sequenze di caratteri multibyte specificate da qualsiasi sequenza di carattere adiacenti e token letterali a stringa larga vengono concatenate in una singola sequenza di caratteri multibyte. Se uno qualsiasi dei token sono token letterali a stringa larga, la sequenza di caratteri multibyte risultante viene trattata come una corda ampia letterale; Altrimenti, è trattato come una stringa di personaggi letterale.

Quindi potresti presentare un reclamo. Probabilmente, la versione precedente dello standard C (aka "C89" aka "C90" aka "Ansi C") non ha imposto la fusione di stringhe larghe con stringhe non larghe. Sebbene C99 abbia ora più di dieci anni, sembra che Microsoft non abbia interesse a rendere conforme il suo compilatore C. Alcuni utenti hanno riferito di essere in grado di accedere ad alcune funzionalità "C99" compilando il codice C come se fosse un codice C ++, perché C ++ include queste funzionalità - e per C ++, Microsoft ha fatto uno sforzo. Ma questo non sembra estendersi al preprocessore.

Nel dialetto C89, penso che ciò che stai cercando non sia possibile (in realtà ne sono abbastanza sicuro, e dal momento che ho scritto il mio preprocessore, penso di sapere di cosa sto parlando). Ma potresti aggiungere un parametro extra e propagarlo:

#define W(x)          W_(x)
#define W_(x)         L ## x
#define N(x)          x
#define STR(x, t)     STR_(x, t)
#define STR_(x, t)    t(#x)

#define LOCATION_(t)  t(__FILE__) t("(") STR(__LINE__, t) t(")")
#define LOCATION      LOCATION_(N)
#define WLOCATION     LOCATION_(W)

che dovrebbe funzionare su GCC e Visual C (almeno, funziona per me, usando Visual C 2005).

Nota a margine: non dovresti definire le macro con un nome che inizia con un sottolineaggio. Questi nomi sono riservati, quindi utilizzandoli potresti scontrarsi con alcuni nomi utilizzati nelle intestazioni di sistema o nelle versioni future del compilatore. Invece di _WIDEN, uso WIDEN_.

Altri suggerimenti

Per concatenare due ampie stringhe letterali che potresti usare

L"wide_a" L"wide_b"

Quindi potresti definire

#define WLOCATION WIDEN(__FILE__) L"(" WIDEN(STR(__LINE__)) L")"

(Nota: non testato su MSVC ++)

Il solo utilizzo di una stringa larga vuota dovrebbe funzionare:

 #define WLOCATION L"" __FILE__ "(" STR(__LINE__) ")"
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top