@Acaunt

Вопрос по оформлению кода C++?

1) Как называть переменные:
int first_name;
// Или
int secondName;

Мне больше нравится первый вариант

2) Что лучше присваивать булевым переменным:
bool i = 0;
bool foo1() {
    return 1;
}
// Или
bool j = false;
bool foo2() {
    return true;
}

3) Как лучше называть переменые итераторы во вложенных циклах:
for (int a = 0; a < 10; a++) {
    for (int b = 0; b < 10; b++) {
        // Некий код
    }
    for (int b = 0; b < 10; b++) {
        for (int c = 0; c < 10; c++) {
            // Некий код
        }
    }
}

Я обычно пишу по алфавиту, и даже где 1 цикл

4) Очень локальный вопрос стоит ли писать else, если ниже нет другого кода ниже:
for (int a = 0; a < 10; a++) {
    if (a == 5) {
        break;
    }
    std::cout << "Не то значение" << std::endl;
}
// Или
for (int a = 0; a < 10; a++) {
    if (a == 5) {
        break;
    }
    else {
        std::cout << "Не то значение" << std::endl;
    }
}

6) Писать ли пробел между стандартными функциями и скобками:
if () {}
for () {}
while () {}
// Или
if() {}
for() {}
while() {}

Я обычно пишу пробел

7) Тот же вопрос только про функции, что я сам написал:
foo1 ();
// Или
foo2();

Обычно здесь я не пишу пробел
  • Вопрос задан
  • 217 просмотров
Решения вопроса 3
@dima20155
you don't choose c++. It chooses you
Я бы полистал уже готовые рекомендации по стилю. Из них можно подчеркнуть интересные вещи, которые могут сказаться даже на качестве самого ПО и потенциальных ошибках.
Вот пример.
https://google.github.io/styleguide/cppguide.html
Ответ написан
gbg
@gbg Куратор тега C++
Любые ответы на любые вопросы
ГЛОБАЛЬНО:

Тратить время, внимание и силы на педантичный подсчет пробелов и расстановку скобок - контрпродуктивно. Достаточно настроить автоформат перед коммитом и сосредоточиться на корректности кода.

1) Равноправно, но первое веет PEP8
2) Однозначно true/false. Возможность прямого каста чисел в логику является тяжлым наследием C и ведет к интересным потенциальным багам.
3) Обычно i, j, k потому что олдовые программисты учили в первую очередь математику, а потом уже алфавит. А если вложений больше трех, пора браться за рефакторинг.
4) Нет, не стоит. Цель как раз в том, чтобы выпрыгнуть из блока как можно раньше, а не вкладывать блоки друг в друга. Опять же, если вложений больше трех - в рефакторинг
5) Вы пропустили этот пункт, тренируйте внимание
6 - 7) Вкусовщина, лично я не пишу эти пробелы. Но я и не использую египетские скобки для циклов (а вы - используете)
Ответ написан
@MarkusD Куратор тега C++
все время мелю чепуху :)
Каждый вопрос здесь подразумевает довольно большой объем информации при обосновании ответов. В общем смысле весь вопрос сводится к выбору одного из стилей написания кода.
Обычно стиль кода закреплен стандартом языка, но в стандарте C++ такого нет. Поэтому стиль кода в C++ является предметом выбора каждого. Опять же, обычно для C++ стиль кодирования выбирают наобум, просто потому что понравилось так или потому что в этом стиле пишет любимая компания (GCS - хороший пример выбора на эмоциях и яркий пример очень плохого стиля для C++). Но обоснование своего выбора является очень важным.
В C++ Core Guidelines есть отдельная секция с описанием стиля кодирования стандартной библиотеки.
И тем не менее.

1) Как называть переменные:

Зависит от того, как будут называться функции и константы.
И вот почему
Книжки читают быстро, а код - еще быстрее. При беглом чтении всегда нужно уметь разделять переменные, константы и функции. C++ итак сложный, а если все будет написано в одной манере, то код на C++ будет только еще сложнее.
Моей рекомендацией будет переменные и локальные константы писать в lower_cast_snake_style, а глобальные константы, макроопределения и элементы нестрогих перечислений писать в UPPER_CAST_SNAKE_STYLE.
Таким образом достигается единообразие. Стиль змейки во всех своих видах сразу отходит под описание данных, создавая акцент для читателя. Таким образом данные будут читаться легче.
Свои типы, имена элементов строгих перечислений, имена пространств и имена функций с методами, при этом, стоит писать в UpperCamelCase. Почему все эти и только в одном стиле. А потому что они и концептуально связаны, и разделены настолько, что не перемешиваются при чтении.
Все составные типы формируют свои пространства имен для вложенных объявлений. Поэтому строгое перечисление, структура, класс или пространство имен разумно называть в едином стиле.
Функции являются точками входа в подпрограмму, их стилистически неверно было бы писать, например, в lowerCamelCase. Первая заглавная буква много значит при чтении, она является акцентом для читателя.


2) Что лучше присваивать булевым переменным:

Литералы 0 и 1 имеют тип int. Если тип переменной - bool, то с какой стати справа от типа должны присутствовать значения с типом int?
Следует использовать только литералы с типом bool: true и false.
И вот почему
При написании кода самым важным является не отражение алгоритма или формальное соответствие стандарту, а именно не вызывать вопросов у читателя. Нужно всегда понимать, что у читателя свой контекст, читатель решает свою задачу, здесь у тебя в коде он только для сбора информации. Его не должны сбивать с толку никакие изыски в написанном коде. Когда читатель видит слева тип bool, а справа значение с типом int, у него появляются вопросы, закрадывается подозрение в достоверности прочитанного, он выпадает из своего контекста. Это - очень плохо.


3) Как лучше называть переменые итераторы во вложенных циклах:

Абсолютно каждое имя должно отвечать на вопрос: "Зачем ты тут существуешь?"
Могут ли однобуквенные имена ответить на этот вопрос внятно через всего одну свою букву? Нет.
Имя - это смысл. Имя - это причина существования. Имя - это цель использования.
И вот почему
Чтение кода вынуждает читателя создавать и поддерживать некоторый контекст читаемого кода. Чем сложнее читателю дается поддержка такого контекста, тем менее понятен читаемый код и тем больше времени уйдет на его изучение. Если же в результате читателя выкинет из контекста решаемой им задачи, то это будет совсем плохо и виноват в этом будет именно плохо написанный код.
Написанное в коде имя создает отметку в контексте для читателя. Чем более это имя понятно и отвечает общему изложению кода, тем легче читателю дается поддержка контекста читаемого кода.
Существует масса концепций именования, море семантических пар имен, гора ярких и кучи общих имен. Важным остается только одно - переменная должна своим именем говорить о том, что она хранит, а функция - что делает. Тип должен в своем имени раскрывать природу существования своих объектов.
Имя должно быть обязательно конкретным. Data, Interface, Iterator - это общие имена, которые не несут никакой конкретики. Общие имена допускаются только в абстрактном коде, т.е. в коде интерфейсов, шаблонов, макросов. Между именем вызываемой функции и именем переменной, принимающей результат вызываемой функции должна быть семантическая связь. И разрыв этой связи допускается только при переходе от общего имени к конкретному. Например так: auto hosts = local_network.GetIterator();. И ведь тут с полпинка все становится понятно, даже думать не надо.


4) Очень локальный вопрос стоит ли писать else, если ниже нет другого кода ниже:

Ветвление всегда подразумевает ровно один прыжок или продолжение исполнения кода. Иногда ветвление подразумевает два прыжка: или прыжок в начало альтернативной ветви, или прыжок из конца основной ветви за пределы кода ветвления. Оптимизатор сам выбирает лучший вариант реализации ветвления, более выгодную основную ветвь и от писателя в этом процессе мало что зависит. Но для читателя ветвление и циклы всегда подразумевают очень большое усложнение кода. else стоит писать только тогда, когда без него иначе невозможно.
И вот почему
При чтении кода важно чтобы код был понятен читателю. Когда в коде появляется ветвление, читатель вынужден раздвоить контекст читаемого кода для себя. Это всегда сложно. Если читатель видит только одну ветвь в ветвлении, второй контекст читателю дастся легче. Если читатель видит что у ветвления есть две ветви, они будет вынужден напрячься чтобы поддержать сразу два контекста в параллели. И если в конце окажется что вторая ветвь ветвления - это лихо замаскированная линейная часть остатка кода до конца подпрограммы, у читателя снова появятся большие вопросы к целям такого изложения кода.


6) Писать ли пробел между стандартными функциями и скобками:

Пробелы нужны для разделения связанных цепочек символов - слов. Код - это запись рассуждений автора о том, что должна делать программа. Код должен читаться как рассказ, в котором слова правильно разделены между собой и правильно расставлены смысловые акценты.
И вот почему
Пробелы нужны чтобы отделить одно от другого. С какой целью? Наверное с целью обратить внимание читателя на то, что пробелами отделено. Пробелы сами не являются акцентами, но позволяют акцентировать внимание читателя, в то время как любые другие символы только забирают на себя внимание потому что читателю надо понять смысл присутствия символов в месте их присутствия.
a==5 - никаких акцентов, ничего не видно. Даже с подсветкой синтаксиса 5 и == читаются плохо и практически неотличимы от a=5 при беглом чтении. В такие моменты у читателя в контекст вносится ошибка или, как минимум, неопределенность ошибки. Но основная цель писателя кода - это написать понятный для чтения код. Поэтому через пробелы надо акцентировать внимание читателя именно на символе эквивалентности - a == 5, позволяя ему правильно прочитать написанное при беглом чтении.
if(a == 5){ - в этом коде видно только акцент на знаке эквивалентности, но не на выражении условия. if (a == 5) { - уже лучше, но скобки требуют от читателя понять природу их нахождения, что это именно условие, а также вчитаться в левый и правый аргументы условия. if( a == 5 ){ - здесь для читателя акцент поставлен именно на всем условии, теряется только знак начала области видимости - {. И именно поэтому египетские скобки - это плохо. Область видимости должна начинаться на своей строке, потому что для нее нужно создать максимально заметный акцент.
for (int a = 0; a < 10; a++) { - тут акценты созданы, но не так, чтобы читатель легко прочитал тип счетчика или операцию шага. for( int a = 0; a < 10; a++ ) - а вот тут внимание читателя акцентируется именно на выражении счетчика. И читателю уже не надо выискивать глазами условия, инициализацию и шаг. Это все выделено пробелами и подано для самого комфортного чтения.


7) Тот же вопрос только про функции, что я сам написал:

С этого момента тебе должно стать понятно, на чем именно нужно делать акценты чтобы не выводить читателя из себя. Главное - это при написании кода всегда помнить, что возможно читать его будет натуральный маньяк-психопат, который точно знает где ты живешь. И ты точно не хочешь разгневать его своим кодом. :)
И вот почему
Код всегда пишется для читателя. Не для транслятора, не для чего-то еще. Транслятору важно только формальное соответствие кода стандарту. Читателю важно понять логику кода, а для этого код надо читать и разбираться в его логических связях. Поэтому, когда пишешь код, всегда нужно думать о том, как его будут читать, не будет ли вопросов к конкретным строчкам, понятны ли имена и отражает ли написанное вложенную в этот код логику.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@rPman
Coding style должен быть таким, как определено в вашей команде
Если это твоя команда - решение принимать нужно после общения со своей командой, выбрав тот стиль, наименее конфликтующий с их стилями.

Если это твой проект - делай так как тебе удобно, я серьезно.
Можно в качестве основы почитать про мировую практику, причем смотри, с какой целью это делается.
Ответ написан
mayton2019
@mayton2019
Bigdata Engineer
Вопрос по оформлению кода C++?

Если делаешь себе пет-проекты или фрилансишь - то безразлично. Делай как читабельно лично
для тебя. Из best-practices. Старайся уменьшать количество вложенных for/if/else. Для
уменьшения - делай декомпозицию на функции. И добавляй guard-expressions с выходом
в return сразу когда какое-то условие выполняется. Часто это уменьшает число вложенной логики.
break - как аналог guard только для циклов.

Если ты зашел в корпорацию - то первое что ты увидишь - это тонны легаси кода и корпоративные
требования (локализованные под проект) о том как надо писать. Конвенции. Соглашения.
И просто договорняки в команде. Например у нас было такое что в проекте мы после пары
багов решили писать switch/case с комменарием в секции default ВСЕГДА в том случае
когда default не содержал логики. Тоесть программист как-бы подтверждал что все
кейсы учтены и мы ничего не потеряли в проверках.
switch(weekday) {
  case SAT: 
     onSaturday();
  default:
     // Nothing to do!
}

Фигурные скобочки и пробелы обычно подсвечивают корпоративные плагины в IDE с настройками.
Еще вариант что стиль чекается во время процедур CD/CI и выдает ошибки или предупреждения
о нарушении стиля. Тоесть сильно упарываться сейчас этим вопросом не стоит. Когда тебя
прижмет - привычка писать правильно появится очень быстро. За считанные недели.

Следующий пример цикла - просто неудачен.
for (int a = 0; a < 10; a++) {
    if (a == 5) {
        break;
    }
    std::cout << "Не то значение" << std::endl;
}

Здесь можно доказать что он на самом деле сводится к циклу от 0 до 4. И вообще без проверки внутри.

Видишь очень важно правильно подбирать учебные примеры.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы