Комментарий — это текст, который компилятор выбрасывает. Он существует исключительно для тех, кто будет читать код позже, и обычно один из этих людей — вы сами. В 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 после: препроцессор удаляет всё между ними, и это переживает любые комментарии и кавычки внутри.