Почему препроцессор дает пространство?

Я хочу прокомментировать строку с помощью препроцессора:

#define open /##*

#define close */

main()
{
        open commented line close
}

когда я делаю $gcc -E filename.c Я ожидал

/* commented line */ 

но я добрался

/ * commented line */ 

так, чтобы компилятор показал ошибку

Почему это дает нежелательное пространство?

7
задан Brian Tompsett - 汤莱恩 22 February 2016 в 19:55
поделиться

5 ответов

Препроцессор запускается и создает код в форме, понятной компилятору C. Он обрабатывает ваш код только один раз, поэтому даже если вы можете создать / * с вашим #define , компилятор увидит / * и выдает ошибку, потому что это недопустимый код C (это инструкция предварительной обработки).

Это не кажется очень хорошим делом.

3
ответ дан 6 December 2019 в 11:48
поделиться

Ошибка связана с тем, что / * не является допустимым токеном.

Как поясняется в документе CPP :

два токена, которые вместе не образуют действительный токен, не могут быть вставлены вместе. Например, вы не можете объединить x с + в любом порядке.

Вы можете получить ошибку, вставив другую ерунду, например / ## + или + ## - .


Что касается пробела, то он вставлен намеренно, чтобы не создать комментарий и не испортить остальное. Из исходного кода GCC :

    /* Avoid comment headers, since they are still processed in stage 3.
         It is simpler to insert a space here, rather than modifying the
         lexer to ignore comments in some circumstances.  Simply returning
         false doesn't work, since we want to clear the PASTE_LEFT flag.  */
      if ((*plhs)->type == CPP_DIV && rhs->type != CPP_EQ)
        *end++ = ' ';
5
ответ дан 6 December 2019 в 11:48
поделиться

Потому что комментарии заменяются пробелами до (и только до) запуска препроцессора. Если вы вставите вместе символы / и * с помощью препроцессора, вы получите /*, что является просто парой операторов. Edit: такое злоупотребление ## технически создает /* как один токен, который имеет неопределенное поведение. Вы можете склеивать > ## > или < %:%: :, хотя этого делать не следует.

См. §6.4.6 C99 о том, какие лексемы разрешено строить, и 6.10.3.3 о процессе катенации.

3
ответ дан 6 December 2019 в 11:48
поделиться

Если вы хотите прокомментировать какой-либо код с помощью препроцессора, используйте

#if 0
...
#endif
0
ответ дан 6 December 2019 в 11:48
поделиться

Из документации по препроцессору GNU C:

Однако два токена, которые вместе не образуют действительный токен, не могут быть вставлены вместе. Например, вы не можете объединить x с + в любом порядке. Если вы попытаетесь, препроцессор выдаст предупреждение и выдаст два токена. Не определено, помещает ли он пробелы между токенами. Часто встречается ненужное использование символа '##' в сложных макросах. Если вы получили это предупреждение, скорее всего, вы можете просто удалить '##'.

В этом случае '*' и '/' не образуют действительный токен C или C ++. Таким образом, они испускаются с пробелом между ними.

(Кроме того: вы, вероятно, получите ошибки компиляции C, даже если вам удастся вставить «комментарии» в вывод препроцессора C. Там не должно быть никаких комментариев.)

{{1 }}
6
ответ дан 6 December 2019 в 11:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: