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

Следующий код мы написали во время работы над статьей «Обработка даты привлекает баги или 77 дефектов в Qt 6».

Анализатор PVS-Studio выделил этот фрагмент кода и выдал предупреждение: V575 [CWE-628] Функция memcpy не копирует всю строку. Используйте функцию «strcpy / strcpy_s», чтобы сохранить терминальный нуль. qplaintestlogger.cpp 253. Собственно вот он:

const char *msgFiller = msg[0] ? " " : "";
QTestCharBuffer testIdentifier;
QTestPrivate::generateTestIdentifier(&testIdentifier);
QTest::qt_asprintf(&messagePrefix, "%s: %s%s%s%s\n",
                   type, testIdentifier.data(), msgFiller, msg,
                   failureLocation.data());
// In colored mode, printf above stripped our nonprintable control characters.
// Put them back.
memcpy(messagePrefix.data(), type, strlen(type));
outputMessage(messagePrefix.data());

Обратите внимание на вызов функции memcpy. Сам этот код вызывает сразу два вопроса:

  • Что-то записывается в буфер, содержимое которого только что было сгенерировано с помощью функции типа printf. Кто так делает?
  • Терминальный ноль не копируется. Вы уверены, что это не ошибка? Анализатору это не нравится.

К счастью, комментарий сразу дает понять. Некоторые непечатаемые символы необходимо восстановить.

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

Для сравнения взгляните на другой фрагмент кода из того же файла:

char buf[1024];
if (result.setByMacro) {
  qsnprintf(buf, sizeof(buf), "%s%s%s%s%s%s\n", buf1, bufTag, fill,
            buf2, buf2_, buf3);
} else {
  qsnprintf(buf, sizeof(buf), "%s%s%s%s\n", buf1, bufTag, fill, buf2);
}
memcpy(buf, bmtag, strlen(bmtag));
outputMessage(buf);

Программист забыл оставить аналогичный комментарий здесь. Вот почему все изменилось. Новый член команды, который должен поддерживать и модифицировать этот код, может немного запутаться. Вообще непонятно, зачем здесь этот memcpy. Более того, непонятно, почему содержимое некоего буфера buf1 было напечатано в начале строки, а содержимое буфера bmtag добавлено в начало строки. Струна. Так много вопросов, так мало ответов. Не пишите так.