Проблема препроцессора C в Microsoft Visual Studio 2010 - PullRequest
2 голосов
/ 17 мая 2010

Я столкнулся с проблемой с новым Visual C ++ в VS 2010.

У меня есть заголовок со следующими определениями:

#define STC(y) #y
#define STR(y) STC(\y)
#define NNN(y) 0##y
#define NUM(y) NNN(y)

Смысл в том, что вы можете иметь некоторую константу, например,

#define TOKEN x5A

и вы можете получить токен в виде числа или строки:

NUM(TOKEN) -> 0x5A
STR(TOKEN) -> "\x5A"

Это ожидаемое поведение в соответствии с правилами подстановки аргументов макросов, и до сих пор оно хорошо работало с gcc, open watcom, pellesC (lcc), Digital Mars C и Visual C ++ в VS2008 Express.

Сегодня я перекомпилировал библиотеку с VS2010 Express только для того, чтобы обнаружить, что она больше не работает! Используя новую версию, я бы получил:

NUM(TOKEN) -> 0x5A
STR(TOKEN) -> "\y"

Похоже, что новый препроцессор обрабатывает \y как escape-последовательность даже внутри макротела, что является бессмысленным, поскольку escape-последовательности имеют смысл только в литеральных строках.

Я подозреваю, что это серая область стандарта ANSI, но даже если исходное поведение было предписано стандартом, MS VC ++ не совсем известен тем, что он на 100% совместим с ANSI C, поэтому я предполагаю, что придется жить с новое поведение компилятора MS.

Учитывая, что, есть ли у кого-нибудь предложения о том, как повторно реализовать исходное поведение макросов с VS2010?

EDIT: исправлен макрос NUM()

РЕДАКТИРОВАТЬ: Возможное решение

Я думаю, что нашел способ сделать это:

#define STC(y) #y

#if defined(_MSC_VER) && (_MSC_VER >= 1600)
#define STA(x,y) STC(x##y)
#define STR(y) STA(\,y)
#else 
#define STR(y) STC(\y)
#endif

#define NNN(y) 0##y
#define NUM(y) NNN(y)

Теперь я получаю:

#define TOKEN x2E

NUM(TOKEN) -> 0x2E
STR(TOKEN) -> "\x2E"

Конечно, gcc жалуется на присоединение обратной косой черты к литералу (\ ## x2E), потому что результат не является допустимым символом препроцессора, но MS выглядит счастливым, поэтому #ifdef.

Я буду рад узнать, если у кого-нибудь есть лучшее решение!

Ответы [ 4 ]

5 голосов
/ 17 мая 2010

Вы полагаетесь на странное нестандартное поведение компилятора.

Ваш макрос NUM написан неправильно. Он никогда не должен был работать ни в старой, ни в новой версии компилятора. Когда вы делаете NUM(TOKEN), результатом расширения макроса в любом стандартном компиляторе будет 0TOKEN, а не 0x5A. Чтобы ваш макрос NUM работал так, как задумано, вы должны реализовать его в двух уровнях:

#define NUM_(y) 0##y
#define NUM(y) NUM_(y)

Единственная причина, по которой это "сработало" для вас до сих пор, это просто еще одна ошибка в компиляторе.

Я пока не уверен, что происходит с делом STR. Компилятор действительно жалуется на нераспознанную escape-последовательность. Должна быть ошибка в компиляторе.

1 голос
/ 18 мая 2010

Я думаю, что это правильное определение для STR (y). Работал в тестовой программе под gcc и, похоже, использует обычные методы макросов.

#define STC(y)      #y
#define STR(y)      "\\" STC(y)
1 голос
/ 17 мая 2010

Если вы используете

#define STR(y) STC(\\y) 

тогда у меня это работает с VS2010.

0 голосов
/ 17 мая 2010

MSVC - это не компилятор C, это компилятор C ++. Компилятор C даже не предлагает некоторые функции C99, и он не предназначен для того, чтобы быть конкурентоспособным современным компилятором C.

Я также собираюсь подвергнуть сомнению ваше использование препроцессора таким образом - мне кажется, это больше, чем маленький ОТТ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...