2009-07-30 11 views
5

Mam makro tak (nie dokładnie, ale funkcja jest dość równoważne):Różnice w Makro operatora ## konkatenacji między visual C++ i gcc

#define STRUCTMEMBER(Member,Value) GlobalStructInstance. ## Member = Value 
... 
STRUCTMEMBER(Item,1); 

Działa to doskonale w Visual C++, ale gcc 3.4.5 (MingGW) generuje następujący błąd:

pasting "." and "Item" does not give a valid preprocessing token

Dzieje się tak również, gdy korzystam z operatora "->". Nie znalazłem wskazówek dotyczących konkatenacji, że korzystanie z tych operatorów jest zabronione.

Czy ktoś ma pomysł?

+1

http://gcc.gnu.org/ml/gcc-help/2003-04/msg00213.html Jakiekolwiek użycie? – AakashM

+0

Przestrzenie celowe? – EFraim

+0

cóż, czytałem dokumentację gcc i dlatego wyjaśniłem ## usuwając wszystkie spacje, więc po prostu wstawiłem je dla czytelności. Moja pierwsza wersja nie ma spacji ... –

Odpowiedz

7

Może Visual C++ wkleja kilka spacji, aby utworzyć inne miejsce. Nie to, że białe spacje są tokenami, ale pozwoliłoby to na działanie twojego kodu.

object.member nie jest tokenem, to trzy tokeny, więc nie trzeba wklejać tokena, aby zaimplementować makro, które opisujesz. Po prostu usuń "##" i powinno działać wszędzie.

[Edytuj: właśnie sprawdzone, a wynik użycia ## do utworzenia czegoś, co nie jest ważnym tokenem, jest niezdefiniowany. Więc GCC może go odrzucić i MSVC wolno zignorować i wykonywać żadnej pasty, o ile mogę powiedzieć]

+0

Dzięki, nie wiem dlaczego, ale kiedy wypróbowałem to pierwszy w ten sposób to nie działało ... z tego powodu próbowałem operatora ## .. teraz wygląda całkiem nieźle! –

4

Z gcc c preprocessor docs.

However, two tokens that don't together form a valid token cannot be pasted together.

structure.member nie jest pojedynczy żeton .

W tym przypadku nie trzeba używać operatora ## (token concatenation). Możesz go po prostu usunąć. Oto przykład testowane gcc 4.2.4 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; 
} 
5

Zgodnie z normą C, w wyniku „##” operatora wstępnego przetwarzania musi być „przerób znacznik” lub wynik jest niezdefiniowany (C99 6,10 .3.3 (3) - operator ##).

Listę tokenów przebiegu wyprzedzającego (C99 6,4 (3) - elementy leksykalne):

header names, identifiers, preprocessing numbers, character constants, string literals, punctuators, and single non-white-space characters that do not lexically match the other preprocessing token categories.

GCC pozwala wiedzieć, że jesteś wjazdem na terytorium niezdefiniowany. MSVC jest w milczeniu zadowolony z nieokreślonego wyniku (to, czego można się spodziewać).

Pamiętaj, że jeśli nie tworzysz ani jednego tokena, to nie potrzebujesz operatora wklejającego token. Ogólnie (jestem pewien, że prawdopodobnie istnieje wyjątek lub dwa), 2 tokeny oddzielone spacjami są równoważne 2 tokenom nieoddzielonym białymi znakami - tak jak w twoim przykładzie.