ну ето конечно баян. Тока я уже задолбался копать в гугле. хочу узнать в каком порядке и в какую последовательность раскроется вызов макроса __drv_functionClass, если используется msvc. Код (Text): #define __drv_functionClass(x) __drv_out(__drv_declspec("SAL_functionClass(\""#x"\")")) #define __drv_out(annotes) __post __$drv_group(##__drv_nop(annotes)) #define __drv_declspec(x) __declspec(x) вот например: "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\WinNT.h" , line 1202 __drv_functionClass(EXCEPTION_ROUTINE) по стандарту процесс идет примерно в такой последовательности(если ниче не путаю): 1.замещение макроса __drv_functionClass 2.обрабатываем оператор # __drv_out(__drv_declspec("SAL_functionClass(\"EXCEPTION_ROUTINE\")")) 3. раскрываем макрос __drv_out __post __$drv_group(##__drv_nop(annotes)) здесь встречается оператор склеивания, но рядом с ним нет параметра для склеивания. Вот здесь и спотыкаются левые препроцессоры( если честно, они спотыкаются и на знаке $). Обычно они выдают ошибку, что (__drv_nop не является preprocessing token.
Код (Text): #define __drv_nop(x) x #define __$drv_group(annotes) __drv_declspec("SAL_begin") annotes __drv_declspec("SAL_end") соответсвенно.
По ходу дела возник след вопрос. Относится ли пример из предыдущего поста к правилу из стандарта 9899:1999 6.10.3.11 "If there are sequences of preprocessing tokens within the list of arguments that would otherwise act as preprocessing directives, the behavior is undefined."
сам себе отвечу Не является, так как ## - это не директива препроцессора. а оператор в макроподстановке.
как я понимаю, такая чехарда с предварительной подготовкой исходного текста для компиляции (preprocessing), связана с тем, что не соблюдаются шаги трансляции. в стандарте определена след последовательность. 1. нормализуется буквенное отображение исходного текста ( убираются триграфы и тп) 2. соединяются логические строки текста. 3. текст разбирается на единицы (pp tokens) и нули(whitespaces). Комментарии замещаются нуликом. Знаки конца строки сохраняются. 4. обрабатываются директивы препроцессора, выполняются макроподстановки. в конце етой фазы директивы и макросы удаляются. Ост фазы я пропускаю. Итак в лучшем варианте все ето должно происходить последовательно в несколько проходов. Но в действительности все ети шаги выполняются за 1 проход по исходному тексту. --------------- Еще раз акцентирую внимание, что 4 фаза принимает на вход разобранный на единицы препроцессора текст, а не сырую последовательность букв. Препроцессор воспринимает на входе след.: - имя заголовочного файла - идентификатор - буква-константа - число - строка - знаки препинания - и все ост. в виде отдельного буквенного знака
В свете информации из предыдущего поста. После слияния ( и __drv_nop получаем (__drv_nop, который не является единицей препроцессора. 6.10.3.3.3 гласит, что "If the result is not a valid preprocessing token, the behavior is undefined." Получается, что препроцессор msvc в нестандартном режиме воспринимает на вход не только pp_tokens, но и сырой неразобранный текст. Остялось тока выяснить, pp msvc выполняет вызов __drv_nop до или после выполнения оператора ##.