Реалізація кутових дужок GCC включає в себе. Чому це має бути таким, як описано нижче?


11

Цей документ у розділі 2.6 Computed Includes має такий параграф:

Якщо рядок розширюється до потоку токенів, що починається з <лексеми і включає> маркер, то лексеми між <і першим> об'єднуються, щоб утворювати ім'я файлу, яке потрібно включити. Будь-який пробіл між маркерами зводиться до одного простору; то будь-який простір після початкового <зберігається, але пробіл перед закриттям> ігнорується . CPP шукає файл відповідно до правил для кутових дужок.

Я знаю, це визначено реалізацією, але чому це має бути таким чином для GCC? Я конкретно маю на увазі вище виділене речення.

EDIT

Я щойно помітив, що третій абзац перед цитованим вище говорить наступне:

Ви повинні бути обережними, визначаючи макрос. #defineзберігає лексеми, а не текст. Препроцесор не може знати, що макрос буде використовуватися як аргумент #include, тому він генерує звичайні лексеми, а не ім'я заголовка. Це навряд чи спричинить проблеми, якщо ви будете використовувати подвійні цитати, які досить близькі до рядкових констант. Якщо ви використовуєте кутові дужки, можливо, у вас виникнуть проблеми .

Хтось знає, на яку проблему тут вказують?


6
Найкраща здогадка - розробники GCC вважають, що наявність пробілів у кінці імені файлу - це гидота.
user3386109

1
Імена файлів з провідними та / або проміжними пробілами дуже вибагливі, особливо в Windows.
Ремі Лебо

1
Тільки тому, що він був визначений таким чином, не означає, що його потрібно визначати так. Це не передбачено стандартом.
eerorika

Visual Studio видаляє як початковий, так і кінцевий простір, тому веде себе по-різному. HP ACC поводиться як gcc (можливо, з міркувань сумісності).
Слімак

Іноді документація просто описує те, що відбувається з кодом, а не навпаки, особливо у випадках, коли це не має значення (ви можете використовувати будь-який простір де завгодно, якщо використовуєте подвійні лапки).
rustyx

Відповіді:


8

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

Схоже, що початкова реалізація виникла в 2000-07-03 (два десятиліття тому!). Відповідна частина виглядає так ( джерело ):

  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зберігаються.


Блискуча, чудова відповідь. Це перший раз, коли я маю можливість побачити фрагмент коду в GCC. Дякую за це.
Айроса

Але чи не так, що умова if (t->flags & PREV_WHITE) CPP_PUTC_Q (pfile, ' ');суперечить тому, що сказано в документі: "Будь-який пробіл між маркерами зводиться до єдиного пробілу; ..."?
Айроса
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.