Menu

Комментарии в C: // и /* */ с объяснениями

В C есть два вида комментариев — однострочные // и многострочные /* */ — с разной историей и одной ловушкой вложенности. Разбираем, как пользоваться обоими, а заодно что стоит комментировать, а что нет.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

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

Две формы

Запустите: в выводе одна строка. Оба комментария были удалены ещё до того, как компилятор разобрал программу, — во время выполнения они ничего не стоят и ничего не добавляют к исполняемому файлу.

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

int x = 5;  // присвоить x пятёрку  int y = 6;   /* y так и не объявлена */

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

int total = price /* до налога */ + shipping;

Почему стилей два

/* */ — исконный C, с 1972 года. // пришёл из C++ и был официально добавлен в C только в C99. Эта история объясняет то, что вы заметите, читая старый код: библиотеки, написанные с прицелом на переносимость в C89, используют /* */ даже для однострочных комментариев, потому что // не собрался бы на старых инструментах, которые они всё ещё поддерживали.

Сегодня любой компилятор, с которым вы, скорее всего, столкнётесь, принимает оба варианта. Используйте // для обычных замечаний и /* */ там, где комментарий действительно занимает несколько строк. Если вы целитесь в очень старый встраиваемый компилятор, проверьте поддержку //, прежде чем на неё полагаться.

Комментарии не вкладываются

Вот единственная настоящая ловушка:

/* Пока отключим этот участок
   int a = compute();
   /* классический помощник - не спускать с него глаз */
   int b = a * 2;
*/

Блочный комментарий заканчивается на первом */, то есть на том, что в строке 3. Строки 4 и 5 снова становятся живым кодом, а завершающий */ в строке 6 — синтаксической ошибкой. Сообщение компилятора указывает на последнюю строку и о причине не говорит ровным счётом ничего.

Решение — воспользоваться препроцессором, который вложенность обрабатывает:

#if 0
    int a = compute();
    /* классический помощник - не спускать с него глаз */
    int b = a * 2;
#endif

#if 0 никогда не истинно, поэтому препроцессор удаляет всё до #endif ещё до того, как компилятор это увидит. Этот приём переживает комментарии, кавычки и другие блоки #if внутри, и его легко найти поиском, когда дойдут руки до уборки.

Закомментирование кода при отладке

Временно убрать строку — самое частое повседневное применение комментариев. Когда программа ведёт себя неправильно, отключение по одной инструкции за раз показывает, какая из них важна.

Раскомментируйте printf и запустите снова, чтобы увидеть, как цикл набирает свой ответ. Трассировка выводом не элегантна, но в C она быстра и работает всегда: отладчик расскажет больше, а printf расскажет прямо сейчас.

Две привычки не дают этому превратиться в бардак. Удаляйте закомментированный код, прежде чем коммитить: система контроля версий помнит старую версию за вас. А когда вы намеренно оставляете отключённую строку, напишите рядом почему.

Документирующие комментарии

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

Инструменты вроде Doxygen читают такие структурированные комментарии и генерируют справочную документацию. Собственный стиль Doxygen использует /** ... */ с тегами @param и @return:

/**
 * Переводит градусы Цельсия в градусы Фаренгейта.
 * @param c температура в градусах Цельсия
 * @return та же температура в градусах Фаренгейта
 */
double celsius_to_fahrenheit(double c);

Для собственного кода годится и то и другое. Важно, чтобы комментарий жил рядом с объявлением, которое люди читают, — обычно в заголовочном файле, — а не был закопан в реализации.

Что стоит комментировать

Правило, которое выдерживает столкновение с настоящими проектами: комментируйте почему, а не что.

i++;  // увеличить i          <- не говорит ничего сверх самого кода
/* Пропускаем BOM: файлы, выгруженные из старой системы, начинаются
   с трёх байтов, которые не являются частью данных. */
offset += 3;

Второй комментарий содержит сведения, которых в коде нет нигде. Первый — шум, который рано или поздно начнёт противоречить описываемой строке, потому что комментарии не обновляют вслед за кодом.

Что действительно стоит комментария именно в C:

  • Кто владеет этой памятью. Если функция возвращает указатель, который вызывающая сторона обязана free, напишите об этом. В C это никак не выразить типом.
  • Единицы измерения и диапазоны. int timeout; неоднозначен — секунды или миллисекунды?
  • Неочевидная корректность. Почему цикл останавливается на n - 1, почему это приведение типа безопасно, почему буфер в 256 байт.
  • Намеренные странности. Код, который выглядит как баг, но багом не является, притягивает «исправления» от будущих читателей, если его не подписать.

Этот комментарий оправдывает своё место: строка под ним выглядит лишней, но таковой не является.

Комментарии внутри строк — не комментарии

Последняя деталь. Маркеры комментариев не имеют особого значения внутри строкового литерала или символьной константы:

Обе строки печатаются целиком. Компилятор разбивает строковые литералы на токены прежде, чем искать комментарии, поэтому // в кавычках — просто два символа. (%% в первой строке — это способ вывести буквальный знак процента через printf: одиночный % начинает спецификатор формата.)

Часто задаваемые вопросы

Как написать комментарий в C?

Двумя способами. // это комментарий действует до конца строки. /* это комментарий */ может занимать сколько угодно строк и заканчивается на закрывающем */. Оба удаляются до компиляции, поэтому на программу они не влияют никак.

Поддерживает ли C комментарии //?

Да, начиная с C99. Они заимствованы из C++ и сегодня поддерживаются повсеместно. Отвергают их только по-настоящему древние компиляторы C89 — именно поэтому в очень старом коде для всего, даже для однострочников, используется /* */.

Можно ли вкладывать комментарии в C?

Нет. /* внешний /* внутренний */ всё ещё внешний */ заканчивается на первом */, оставляя всё ещё внешний */ как сломанный код. Чтобы отключить блок, в котором уже есть комментарии /* */, используйте #if 0 ... #endif — он вкладывается корректно.

Как закомментировать блок кода в C?

Оберните его в /* */, если внутри нет блочных комментариев, или поставьте // в начале каждой строки. Надёжный вариант для больших участков — #if 0 до и #endif после: препроцессор удаляет всё между ними, и это переживает любые комментарии и кавычки внутри.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ