Реализация угловых скобок G CC включает. Почему это должно быть так, как описано ниже? - PullRequest
11 голосов
/ 25 апреля 2020

Этот документ в своем разделе 2.6 Вычислено включает в себя имеет следующий абзац:

Если строка расширяется до потока токенов, начинающегося с <токена и включая токен>, токены между <и первым> объединяются, чтобы сформировать имя файла для включения. Любой пробел между токенами сводится к одному пробелу; тогда любой пробел после начального <сохраняется, но завершающий пробел до закрытия> игнорируется . CPP выполняет поиск файла в соответствии с правилами для угловых скобок.

Я знаю, что это определяется реализацией, но почему это должно быть так для G CC? Я имею в виду конкретно выделенное предложение выше.

РЕДАКТИРОВАТЬ

Я только что заметил, что в третьем абзаце перед цитируемым выше сказано следующее:

Вы должны быть осторожны при определении макроса. #define сохраняет токены, а не текст. Препроцессор не может знать, что макрос будет использоваться в качестве аргумента #include, поэтому он генерирует обычные токены, а не имя заголовка. Это вряд ли вызовет проблемы, если вы используете двойные кавычки, которые достаточно близки к строковым константам. Однако, если вы используете угловые скобки, у вас могут возникнуть проблемы .

Кто-нибудь знает, на какую проблему здесь указывают?

1 Ответ

9 голосов
/ 25 апреля 2020

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

Кажется, что первоначальная реализация приземлилась в 2000-07-03 (два десятилетия go!) ). Соответствующая часть выглядит следующим образом ( source ):

  for (;;)
    {
      t = cpp_get_token (pfile);
      if (t->type == CPP_GREATER || t->type == CPP_EOF)
        break;

      CPP_RESERVE (pfile, TOKEN_LEN (t));
      if (t->flags & PREV_WHITE)
        CPP_PUTC_Q (pfile, ' ');
      pfile->limit = spell_token (pfile, t, pfile->limit);
    }

Примечательно, что она вспыхивает, когда видит токен CPP_GREATER (т.е. >), до резервирование памяти для токена. Это имеет смысл, поскольку нет необходимости выделять память, когда токен не будет записан в буфер.

Тогда, только после зарезервированной памяти, препроцессор проверяет, имеет ли токен предшествующий пробел (t->flags & PREV_WHITE) и, когда это происходит, записывает символ пробела в буфер.

В результате в < foo / bar > только пробелы до foo (то есть после начального <), / и bar сохраняются.

...