Проверка стиля в ejudge: частые ошибки

Каждая посылка в ejudge проходит проверку стиля утилитой cpplint.

Что именно проверяется

Команда, которую запускает ejudge:

cpplint --filter="-,+whitespace,+readability,-readability/casting,-whitespace/ending_newline,-whitespace/tab,+build/include_what_you_use" --linelength=140 solution.cpp
ФильтрЧто значит
-сначала выключаем все проверки
+whitespaceвключаем все проверки пробелов, пустых строк, отступов и длины строк (Horizontal Whitespace, Vertical Whitespace)
+readabilityвключаем проверки читаемости: фигурные скобки у if/else, длина функций, оформление TODO и т. п.
-readability/castingне проверяем приведения в стиле C, (int)x разрешено (Casting)
-whitespace/ending_newlineне требуем перевод строки в конце файла
-whitespace/tabне запрещаем табы (Spaces vs. Tabs)
+build/include_what_you_useподключайте заголовок для каждой стандартной сущности, которую используете (Include What You Use)
--linelength=140строка не длиннее 140 символов (Line Length, у нас лимит мягче гугловских 80)

Правила основаны на Google C++ Style Guide. using namespace std;, long long и отсутствие копирайта не проверяются.

Каждая ошибка в выводе выглядит так:

solution.cpp:8:  Missing space before ( in while(  [whitespace/parens] [5]

Это файл, номер строки, описание, категория в квадратных скобках (по ней ищите в таблице выше) и уверенность от 1 до 5.

Частые ошибки

1. Нет пробела перед {

whitespace/braces
int main(){        // ❌
int main() {       // ✅

2. Не подключён нужный заголовок

build/include_what_you_use
#include <iostream>
#include <string>
#include <vector>

3. Пробелы в конце строки

whitespace/end_of_line

Обычно это «пустые» строки, в которых остался отступ. Их не видно глазами, поэтому включите в редакторе «Trim trailing whitespace on save» (удалять пробелы в конце строк при сохранении).

4. Нет пробела после запятой

whitespace/comma
int a,b;                              // ❌
int a, b;                             // ✅
freopen("in.txt", "r", stdin);        // ✅

5. { на отдельной строке

whitespace/braces
int main()
{                  // ❌
int main() {       // ✅ открывающая скобка в конце предыдущей строки

6. Нет пробела между for/while/if и (

whitespace/parens
for(int i = 0;i < n;i++){          // ❌ сразу три ошибки
for (int i = 0; i < n; i++) {      // ✅
while (cin >> x) {                 // ✅

7. Нет пробелов вокруг операторов

whitespace/operators
cin>>a>>b;  cout<<x;  i<n;  a=b;               // ❌
cin >> a >> b;  cout << x;  i < n;  a = b;     // ✅

8. Пустая строка в начале или в конце блока { }

whitespace/blank_line
int main() {
                   // ❌ лишняя пустая строка после {
    cout << 1;
                   // ❌ лишняя пустая строка перед }
}

9. Лишние пробелы у круглых скобок

whitespace/parens
signed main () {     // ❌ пробел между именем функции и (
f( x );  if (a ) {   // ❌ пробелы внутри скобок
signed main() {      // ✅
f(x);  if (a) {      // ✅

10. Несколько команд в одной строке / пробел перед ;

whitespace/semicolon
int a, b;cin >> a >> b;   // ❌
return 0 ;                // ❌
int a, b;                 // ✅ одна команда на строку
cin >> a >> b;
return 0;

Реже встречаются for (int x:v) вместо for (int x : v), i ++ вместо i++ и неправильный отступ у public:/private: (нужен ровно 1 пробел от начала класса).

Как запустить cpplint у себя

  1. Установите Python 3 (python.org; на Windows отметьте галочку «Add Python to PATH»).
  2. Установите cpplint:
    python -m pip install cpplint
    На Windows можно py -m pip install cpplint.
  3. Проверьте файл той же командой, что и ejudge:
    python -m cpplint --filter="-,+whitespace,+readability,-readability/casting,-whitespace/ending_newline,-whitespace/tab,+build/include_what_you_use" --linelength=140 solution.cpp
    Все .cpp в папке и подпапках проверяются так: замените solution.cpp на --recursive .

Если вывод состоит только из Done processing solution.cpp, всё чисто и ejudge пропустит посылку. Иначе в конце будет Total errors found: N.

Запуск именно через python -m cpplint работает, даже когда команда cpplint «не найдена». Предупреждение DeprecationWarning: codecs.open() на новых версиях Python не влияет на результат, его можно игнорировать.

Автоисправление: clang-format

clang-format — это программа, которая автоматически расставляет в коде пробелы, отступы, переносы строк и фигурные скобки по заданным правилам. Сам код (что он делает) она не меняет, только его оформление. Настроенный clang-format исправляет все ошибки из списка выше, кроме №2 (про #include): заголовки нужно подключить самостоятельно.

Установите его командой python -m pip install clang-format. В CLion и Visual Studio он уже встроен (см. Настройка в IDE).

Как настроить clang-format

Правила форматирования clang-format берёт из файла настроек .clang-format. Без этого файла он отформатирует код не так, как требует проверка в ejudge.

Требования к файлу:

Содержимое файла целиком (скопируйте как есть):

BasedOnStyle: Google
ColumnLimit: 140
IndentWidth: 4
AccessModifierOffset: -3

Что означает каждая строка:

СтрокаЧто делает
BasedOnStyle: Googleберём за основу стиль Google, на котором основан cpplint: { в конце строки, пробелы после запятых и вокруг операторов, for ( с пробелом, без пробелов в конце строк и т. д.
ColumnLimit: 140переносить строки длиннее 140 символов, как в --linelength=140 у cpplint
IndentWidth: 4отступ внутри блоков 4 пробела
AccessModifierOffset: -3сдвигает public:/private: на 3 пробела левее обычного отступа, то есть оставляет им ровно 1 пробел, как требует cpplint

Где должен лежать файл

clang-format ищет .clang-format в папке с вашим .cpp, затем в папке выше и так далее. Поэтому достаточно положить один файл в общую папку с задачами:

contest/
├── .clang-format
├── A/
│   └── solution.cpp
└── B/
    └── solution.cpp

Как отформатировать и проверить

Отформатировать файл (изменения сохраняются прямо в нём):

clang-format -i solution.cpp

Проверить, что clang-format нашёл ваш .clang-format:

clang-format --dump-config solution.cpp

Среди длинного списка настроек найдите строку ColumnLimit: там должно быть 140 (пробелов после двоеточия может быть несколько). Если там 80, файл не найден: проверьте его имя (нет ли .txt на конце) и папку, в которой он лежит.

Документация: ClangFormat, все опции.

Настройка в IDE

Во всех примерах ниже <ФИЛЬТР> означает строку:

"-,+whitespace,+readability,-readability/casting,-whitespace/ending_newline,-whitespace/tab,+build/include_what_you_use"

CLion

Visual Studio

Code::Blocks

VS Code

Установите расширения C/C++ и cpplint. Форматирование Shift+Alt+F использует ваш .clang-format.

Рецепт перед отправкой

  1. Отформатируйте файл (clang-format из консоли или сочетание клавиш в IDE).
  2. Проверьте #include: каждый используемый заголовок подключён явно, без bits/stdc++.h.
  3. Прогоните cpplint командой выше. Если вывод пустой (кроме Done processing), отправляйте.