Удаляет ли препроцессор C комментарии или сначала разворачивает макросы?[дубликат]

StackOverflow https://stackoverflow.com/questions/1510869

Вопрос

На этот вопрос уже есть ответ здесь:

Рассмотрим эту (ужасную, ужасный, никуда не годный, очень плохой) структуру кода:

#define foo(x) // commented out debugging code

// Misformatted to not obscure the point
if (a)
foo(a);
bar(a);

Я видел, как препроцессоры двух компиляторов генерируют разные результаты в этом коде:

if (a)
bar(a);

и

if (a)
;
bar(a);

Очевидно, что это плохо для переносимой базы кода.

Мой вопрос:Что препроцессор должен с этим делать?Сначала удалите комментарии или сначала разверните макросы?

Это было полезно?

Решение

К сожалению, оригинал Спецификация ANSI C в частности, исключаются любые функции препроцессора в разделе 4 ("Эта спецификация описывает только язык C.Это не предусматривает ни библиотеки, ни препроцессора".).

В Спецификация C99 однако обрабатывает эту эксплицитность.Комментарии заменяются одним пробелом на "этапе перевода", который происходит до разбора директивы предварительной обработки.(Подробности в разделе 6.10).

VC++ и тот Компилятор GNU C оба следуют этой парадигме - другие компиляторы могут быть несовместимы, если они старше, но если это совместимо с C99, вы должны быть в безопасности.

Другие советы

Как описано в это скопированное n-вставленное описание из этапов перевода в стандарте C99 удаление комментариев (они заменяются одним пробелом) происходит на этапе перевода 3, в то время как директивы предварительной обработки обрабатываются, а макросы расширяются на этапе 4.

В стандарте C90 (который у меня есть только на бумажном носителе, поэтому никаких copy-n-paste) эти два этапа выполняются в одном и том же порядке, хотя описание этапов перевода в некоторых деталях немного отличается от стандарта C99 - тот факт, что комментарии удаляются и заменяются одним пробелом перед обработкой директив предварительной обработки и расширением макросов, не отличается.

Опять же, в стандарте C ++ эти 2 фазы выполняются в одном и том же порядке.

Что касается того, как '//' комментарии должны обрабатываться, об этом говорится в стандарте C99 (6.4.9/2).:

За исключением символьной константы, строкового литерала или комментария, символы // представляют комментарий, который включает все многобайтовые символы вплоть до, но не включая, следующий символ новой строки.

И стандарт C ++ гласит (2.7):

Символы // начинают комментарий, который заканчивается следующим переводом строки символ.

Итак, ваш первый пример явно является ошибкой со стороны этого переводчика - ';' персонаж после того , как foo(a) должно быть сохранено, когда foo() макрос расширен - символы комментария не должны быть частью "содержимого" the foo() макрос.

Но поскольку вы столкнулись с глючащим транслятором, возможно, вы захотите изменить определение макроса на:

#define foo(x) /* junk */

чтобы обойти ошибку.

Однако (и я здесь отклоняюсь от темы ...), поскольку сращивание строк (обратная косая черта непосредственно перед новой строкой) происходит до обработки комментариев, вы можете столкнуться с чем-то вроде этого фрагмента неприятного кода:

#define evil( x) printf( "hello "); // hi there, \
                 printf( "%s\n", x); // you!



int main( int argc, char** argv)
{
    evil( "bastard");

    return 0;
}

Что могло бы удивить того, кто это написал.

Или, что еще лучше, попробуйте следующее, написанное кем-то (конечно, не мной!) кому нравятся комментарии в стиле box:

int main( int argc, char** argv)
{
                            //----------------/
    printf( "hello ");      // Hey, what the??/
    printf( "%s\n", "you"); // heck??         /
                            //----------------/
    return 0;
}

В зависимости от того, использует ли ваш компилятор обработку по умолчанию триграфы или нет (предполагается, что это должны делать компиляторы, но поскольку триграфы удивляют почти всех, кто с ними сталкивается, некоторые компиляторы решают отключить их по умолчанию), вы можете получить желаемое поведение, а можете и не получить - каким бы оно ни было, конечно.

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

Никогда не добавляйте // комментарии в свои макросы.Если вам необходимо добавить комментарии, используйте /* */.Кроме того, у вас ошибка в вашем макросе:

#define foo(x) do { } while(0) /* junk */

Таким образом, foo всегда безопасен в использовании.Например:

if (some condition)
    foo(x);

никогда не выдаст ошибку компилятора, независимо от того, определено foo для некоторого выражения или нет.

#ifdef _TEST_
#define _cerr cerr
#else
#define _cerr / ## / cerr
#endif
  • будет работать на некоторых компиляторах (VC++).Когда _TEST_ не определено,

    _серр ...

    будет заменена строкой комментария

    // серр ...

Кажется, я припоминаю, что соблюдение требований требует трех шагов:

  1. Стриптиз
  2. развернуть макросы
  3. раздевайся снова

Причина этого связана с тем, что компилятор может принимать файлы .i напрямую .

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top