Различия в операторе конкатенации Macro ## между Visual-C++ и gcc

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

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

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

вставка "." и «Элемент» не дает допустимого токена предварительной обработки

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

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


person Florian Storck    schedule 30.07.2009    source источник
comment
gcc.gnu.org/ml/gcc-help/2003- 04/msg00213.html любое использование?   -  person AakashM    schedule 30.07.2009
comment
ну, я прочитал документы gcc, и поэтому они объяснили, что ## удаляет все пробелы, поэтому я просто вставил их для удобства чтения. В моей первой версии не было пробелов...   -  person Florian Storck    schedule 30.07.2009


Ответы (3)


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

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

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

person Steve Jessop    schedule 30.07.2009
comment
Спасибо, я не знаю почему, но когда я впервые попробовал это таким образом, это не сработало... из-за этого я попробовал оператор ##... теперь выглядит намного лучше! - person Florian Storck; 30.07.2009

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

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

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

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

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

person Michael Burr    schedule 30.07.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;
}
person Karl Voigtland    schedule 30.07.2009