Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Комментарии в Си

Из документации к языку Си на сайте «Микрософта», секция про комментарии, описывается нестандартное расширение спецификации:

Comments beginning with two forward slashes (//) are terminated by the next newline character that is not preceded by an escape character. […] the newline character is preceded by a backslash (\), creating an «escape sequence». This escape sequence causes the compiler to treat the next line as part of the previous line. (For more information, see Escape Sequences.)

The default for Microsoft C is that the Microsoft extensions are enabled. Use /Za to disable these extensions.

То есть в примере ниже, если его скомпилировать в «Визуал Студио», выражение i++; на самом деле будет частью комментарий и не выполнится:

// мой комментарий \
    i++;

Счастливой отладки!

Добавлено позднее: в компиляторе gcc тоже работает, причём раскрашивается как комментарий в редакторах vim и «Саблайм».

9 комментариев
Валерий 2020

#define true ( (rand() & 17) != 17 )
#define false ( (__LINE__ & 13) == 13 )
#define if(x) if ( (x) && (rand() < RAND_MAX * 0.99) )

Евгений Степанищев 2020

Есть более знаменитое:
#define j i

?

hshhhhh.name 2020

Счастливой отладки!

Так в IDE оно должно быть подсвечено как комментарий.

Евгений Степанищев 2020

В какой именно? В «Студии»? Вероятно, но это может быть часть объёмного чужого кода, подключенного в проект. Глазами его просматривать?

hshhhhh.name 2020

https://i.imgur.com/hPOq7AP.png

Ну такое :)

Евгений Степанищев 2020

Вот и попробуй найти такое в большом проекте, который писался на в «Студии» :)

hshhhhh.name 2020

Глазами его просматривать?

Так это то же самое что просто взять и удалить строку `i++`. И это может быть даже сложнее заметить чем такое комментирование.

Евгений Степанищев 2020

С этим не спорю. Но обычно как бывает. Видишь баг, пишешь автору, он говорит «всё работает у меня, отстань», а у тебя не работает :) Или он даже пытается найти баг, но никак не может.

Разгадка в том, что автор пишет под другой компилятор, где нет таких спецэффектов.

hshhhhh.name 2020

Разгадка в том, что автор пишет под другой компилятор, где нет таких спецэффектов.

#include <stdio.h>
int main() {
int i=0;
i++;
//\
i++;
printf(«%i», i); // 1
return 0;
}

gcc 9.2.0

Евгений Степанищев 2020

И gcc туда же :)

hshhhhh.name 2020

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

Евгений Степанищев 2020

Ну да, это много где принято. В JS и Пайтоне, например.

hshhhhh.name 2020

И gcc туда же :)

Скриншот где i++ было закоментировано был сделан в vim :)

Евгений Степанищев 2020

Иттитская же сила!

Артём Зорин 2020

Не совсем понял, где именно мораль в этой истории.

Обратная косая черта — стандартная штука для склейки строк (получения логической строки, logical source line) в Си. Правда, информация о том, должно ли быть такое поведение в комментариях, неоднозначная.

То, что некоторые среды разработки неверно подсвечивают синтаксис, конечно, плохо.

А ещё обратная косая черта может быть заменена триграфом ??/.

Но оставим это хакерство разработчикам обфускаторов. Единственная реальная проблема, выдвинутая в обсуждении, — когда один и тот же код у разных людей компилируется по-разному. Но не синтетический ли это пример? Возникала ли такая ситуация хоть раз у кого-нибудь?

Евгений Степанищев 2020

Перечитал написанное, несколько туманно получилось, верно. Насколько я понял, такое поведение — микрософтское расширение языка, отключаемое специальным ключом. Поддерживается «Студией» и, как мы выяснили, некоторыми другими компиляторами (в комментариях всплыл gcc).

Про триграфы я знаю, но в «Си++17» они удалены и, насколько я помню, из «Си» они тоже пропали (мой clang 11.0 их уже не понимает). Туда им и дорога, конечно.

Я не уверен насколько пример реальный, но полностью синтетическим его тоже на назовёшь. Мне видится две ситуации:

  • разработчик поставил косую черту случайно, у меня так тоже бывает — напечатаешь в другое окно и даже не заметишь. С развитием систем контроля версий этот вариант маловероятный;
  • комментарий кончающийся на слеш, например пути в «Виндоузе»:

// Может содержать пробел! Например: c:\program files\
TCHAR pf[MAX_PATH];
SHGetSpecialFolderPath(0, pf, CSIDL_PROGRAM_FILES, FALSE);

deadem 2020

Штука тут в том, что однострочные комментарии // впервые появились в C++, а в C они попали с новым стандартом (C99), и на сегодняшний день поддерживатся практически всеми компиляторами. Но для всякой экзотики оставлен флаг /Za для переключения в ANSI-режим (C89), где ещё не было однострочных комментариев.

Эти комментарии в C легальны уже 20 лет ;)

Вероятно, что в MSVC оно попало до принятия C99, отсюда и такой комментарий. Современные компиляторы тоже любят бежать впереди паровоза и внедрять фичи, ещё не принятые комитетом, но уже не включают их по умолчанию.

Цитирую C99:

5.1.1.1 Program structure

  1. Each instance of a backslash character (\) immediately followed by a new-line
    character is deleted, splicing physical source lines to form logical source lines.

6.4.9 Comments

2 Except within a character constant, a string literal, or a comment, the characters //
introduce a comment that includes all multibyte characters up to, but not including, the
next new-line character. The contents of such a comment are examined only to identify
multibyte characters and to find the terminating new-line character.

3 EXAMPLE

«a four-character string literal

#include « undefined behavior

// */ // comment, not syntax error

f=g/**h; equivalent to f=g/h;

//\
i(); // part of a two-line comment

/\
/ j(); // part of a two-line comment

http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf

Евгений Степанищев 2020

Понятно, спасибо! Этого я не знал, на Си 20 лет назад я программировал нечасто и вообще не помню что там было с однострочными комментариям.