Differenze nell'operatore di concatenazione Macro ## tra Visual-C ++ e gcc
-
05-07-2019 - |
Domanda
Sto avendo una macro come questa (non esattamente, ma la funzione è abbastanza equivalente):
#define STRUCTMEMBER(Member,Value) GlobalStructInstance. ## Member = Value
...
STRUCTMEMBER(Item,1);
Funziona perfettamente in Visual C ++, ma gcc 3.4.5 (MingGW) produce il seguente errore:
incollare ". " e "Articolo" non fornisce un token di preelaborazione valido
Questo succede anche quando uso il pulsante " - > " operatore. Non ho trovato suggerimenti sulla concatenazione, secondo cui l'uso di questi operatori è vietato.
Qualcuno ha un'idea?
Soluzione
Forse Visual C ++ sta incollando un paio di spazi insieme per creare un altro spazio. Non che gli spazi bianchi siano token, ma consentirebbe al tuo codice di funzionare.
object.member
non è un token, è tre token, quindi non è necessario incollare token per implementare la macro che descrivi. Rimuovi "##" e dovrebbe funzionare ovunque.
[Modifica: appena spuntato, e il risultato dell'uso di ## per formare qualcosa che non è un token valido non è definito. Quindi GCC può rifiutarlo e MSVC può ignorarlo e non eseguire incolla, per quanto ne so.]
Altri suggerimenti
Secondo lo standard C, il risultato dell'operatore di preelaborazione " ##
" deve essere un "token di preelaborazione" o il risultato non è definito (C99 6.10.3.3 (3) - Il ## operatore).
L'elenco dei token di preelaborazione è (C99 6.4 (3) - Elementi lessicali):
nomi di intestazione, identi, numeri di preelaborazione, costanti di carattere, valori letterali di stringa, segni di punteggiatura e singoli caratteri non bianchi che non corrispondono lessicamente alle altre categorie di token di preelaborazione.
GCC ti fa sapere che stai entrando in un territorio non definito. MSVC è silenziosamente contento del risultato indefinito (è quello che ti aspetteresti che accada).
Nota che se non stai creando comunque un singolo token, non hai bisogno dell'operatore di incollare token. Generalmente (sono sicuro che ci sono probabilmente un'eccezione o due), 2 token separati da spazi bianchi equivalgono a 2 token non separati da spazi bianchi - come nel tuo esempio.
Dai gcc c preprocessor docs :
Tuttavia, due token che non formano insieme un token valido non possono essere incollati insieme.
structure.member non è un singolo token.
In questo caso non è necessario utilizzare l'operatore ## (concatenazione di token). Puoi semplicemente rimuoverlo. Ecco un esempio testato con gcc 4.2.4 su Linux:
#include <stdio.h>
#define STRUCTMEMBER(Member, Value) GlobalStructInstance.Member = Value
struct {
const char* member1;
}GlobalStructInstance;
int main(void)
{
STRUCTMEMBER(member1, "Hello!");
printf("GlobalStructInstance.member1 = %s\n",
GlobalStructInstance.member1);
return 0;
}