Различия в операторе сцепления Macro ## между Visual-C ++ и gcc - PullRequest
5 голосов
/ 30 июля 2009

У меня такой макрос (не совсем, но функция вполне эквивалентна):

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

Это прекрасно работает в Visual C ++, но gcc 3.4.5 (MingGW) выдает следующую ошибку:

вставка "." и "Item" не дает действительный токен предварительной обработки

Это также происходит, когда я использую оператор "->". Я не нашел намеков на конкатенацию, что использование этих операторов запрещено.

У кого-нибудь есть идея?

Ответы [ 3 ]

7 голосов
/ 30 июля 2009

Возможно, Visual C ++ вставляет несколько пробелов вместе, чтобы создать еще один пробел. Не то, чтобы пробелы были токенами, но это позволило бы вашему коду работать.

object.member - это не токен, это три токена, поэтому вам не нужно вставлять токены для реализации макроса, который вы описываете. Просто удалите «##», и он должен работать везде.

[Редактировать: только что отмечен, и результат использования ## для формирования чего-то, что не является допустимым токеном, не определено. Поэтому GCC разрешено отклонять его, а MSVC разрешено игнорировать его и не выполнять вставку, насколько я могу судить.]

5 голосов
/ 30 июля 2009

Согласно стандарту C, результатом оператора предварительной обработки '##' должен быть 'токен предварительной обработки', или результат не определен (C99 6.10.3.3 (3) - Оператор ##).

Список токенов предварительной обработки (C99 6.4 (3) - Лексические элементы):

имена заголовков, идентификаторы, числа предварительной обработки, символьные константы, строковые литералы, знаки пунктуации и одиночные непробельные символы, которые лексически не соответствуют другим категориям токенов предварительной обработки.

GCC позволяет вам знать, что вы входите в неопределенную территорию. MSVC безмолвно рад неопределенному результату (именно этого вы и ожидаете получить).

Обратите внимание, что если вы все равно не создаете один токен, вам не нужен оператор вставки токена. Как правило (я уверен, что, возможно, есть исключение или два), 2 токена, разделенные пробелами, эквивалентны 2 токенам, не разделенным пробелами - как в вашем примере.

4 голосов
/ 30 июля 2009

Из документов препроцессора gcc c :

Однако два токена, которые вместе не образуют действительный токен, не могут быть вставлены вместе.

Structure.member не является одним токеном.

В этом случае вам не нужно использовать оператор ## (конкатенация токенов). Вы можете просто удалить это. Вот пример, протестированный с 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;
}
...