Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [FAQ] Оформление кода, Или как сделать код читабельным 
:(
    Опции темы
bsa
Дата 16.8.2009, 15:04 (ссылка) |    (голосов:9) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Текст программы пишется не для компьютера, а для человека его читающего...


Как такового стандарта оформления кода нет - у каждого он свой. И пытаться навязать какие-то рамки мне бы не хотелось. Надо иметь в виду, что какой бы вы способ оформления ни выбрали, вы должны следовать ему как минимум в пределах одного файла. Но лучше, когда во всем проекте только один стиль.
Рассмотрим только общее, что объединяет стандарты.

1. На одной строке должна располагаться только одна операция
Это правило очень сильно упрощает понимание кода и его отладку.
Еще можно добавить сюда же требование объявлять переменные отдельно друг от друга:
Код
int value;
int array[10];
const int size = sizeof(array)/sizeof(*array);
int x, y; //это возможное исключение - переменные связаны друг с другом по смыслу

2. Названия типов, функций, переменных и пр. должны отражать их суть
Если дать переменной название v, то через пол года никто не сможет понять без заглядывание в код, за что она отвечает. Конечно, если у вас есть цикл на пару строчек, то переменную-счетчик целого типа можно называть просто: i, j, k...
Хорошо оформленный код легко позволяет определить, чем является каждый конкретный символ - одного взгляда достаточно, чтобы, например, отличить функцию от имени класса. Легче всего этого добиться при использовании разных регистров символов. Например:
Код
#define MY_MACRO  //определения препроцессора - полностью большими буквами с подчеркиваниями
typedef std::string MyString; //типы с большой буквы
MyString fileName; //переменные начинаются с маленькой буквы, но первое слово - существительное
MyString readMyFile(); //названия функций с маленькой буквы, но первое слово означает действие
enum { ONE_TWO, THREE_FOUR }; //перечисления большими буквами с подчеркиваниями (есть вариант - аналогично типам)
class MyClass  //название класса - это тоже тип, поэтому с большой буквы
{
private:
   int attribute_; //приватные атрибуты классов заканчиваются подчеркиванием (есть и другие варианты, например: m_attribute)
   std::set<Flags> objectFlags_
};

3. Отступы делать обязательно
Всегда нужно выделять отступами блоки кода, которые выполняются в зависимости от встроенных операторов (циклов, условий). Это сильно упрощает отлов тривиальных ошибок (например, когда нужно выполнение нескольких операций в цикле, не заключенных в фигурные скобки). Например:
Код
for(int i = 0; i < 10; ++i)
   std::cout << i << std::endl;

if (myCondition) {
   processMyData();
}
Отступы делают пробелами или символом табуляции, иногда и тем и другим одновременно. Хочу предостеречь от последнего - всегда делайте отступы только пробелами, или только табуляцией, так как в противном случае весь код расползается при изменении размера символа табуляции - такой код читать очень сложно при других настройках редактора. Некоторые современные среды программирования позволяют автоматически преобразовывать символы табуляции в пробелы и обратно. Таким образом, сохраненный файл всегда имеет отступы в виде пробелов, тогда как в редакторе отступы в виде табуляций.
По умолчанию, символ табуляции имеет размер эквивалентный восьми пробелам. Его использование приводит к тому, что довольно быстро теряется свободное место для кода в строке... С другой стороны, на отступ в один пробел сложно ориентироваться. Поэтому лично я предпочитаю размер отступа равным четырем пробелам. Это компромисс между наглядностью и плотностью текста.
В пределах одного файла (а желательно и всего проекта) нужно придерживаться одного размера отступа. Т.е. чтобы не было, что тело одной функции сдвинуто на 4 пробела от начала строки, а тело другой (равноценной) - на 8.

4. Правило расстановки фигурных скобок должно быть одно для всего файла
Тут опять же четко не определено, как и где их ставить. Но наиболее популярные:
- открывающая на строке оператора:
Код
if (myCondition) {
   processMyData();
}

- открывающая на следующей строке:
Код
if (myCondition)
{
   processMyData();
}

При этом, закрывающая фигуная скобка всегда ставится на новой строке и отступ пред ней такой же, как и перед строкой, на которой стоит открывающая.
Возможны смешанные варианты, когда в одних случаях используется одна схема, а в других - другая. Например, стиль Linux:
Код
namespace NS { //фигурная скобка пространства имен не учитывается даже в отступах

class MyClass
{//только первая фигурная скобка переносится на новую строку
   int method1() { //все последущие идут на той же строке, что и оператор
      if (myCondition) {
         return processMyData();
      }
      return -1;
   }
   int method2();
};

int MyClass::method2()
{
   if (myCondition) {
      removeMyData();
   }
   return 0;
}

} //namespace NS

5. Не скупитесь на пустые строки
Очень часто в одной функции выполняется последовательность неких действий, каждое из которых состоит из нескольких вызовов. Очень хорошо смотрится код, в котором эти действия разделены пустыми строками. Так же, в данном случае не помешает комментарий на пару слов, дающий общее представления о действии, которое идет ниже.
Код
int x = 10, y = 5;
//считаем длину вектора, заданного x,y
double x2 = x*x;
double y2 = y*y;
double value = sqrt(x2 + y2);

std::cout << value << std::endl; //здесь комментарий не требуется, так как все понятно

6. Большие функции - это зло
Хорошим стилем программирования считается, когда у вас функция имеет размер не более трёх десятков строк. Конечно, бывают случаи, когда сложный алгоритм не позволяет безвредно разбить функцию на несколько. Но они случаются крайне редко. Поэтому, если у функции получилось большое тело, то надо ее разделять на составные. Выделять стоит в первую очередь то, что в последствии можно будет использовать отдельно.

7. Не стоит делать функции с более чем 3-мя параметрами
Чем больше параметров, тем сложнее запомнить, что и в какой последовательности надо передавать. Иногда помогает разбиение на несколько функций, иногда - объединение параметров связанных по смыслу в структуры.

8. Узкоспециализированные функции/классы предпочтительней универсальным
Предположим, вам нужно сегодня перевезти пару сумок вещей на дачу. Завтра может понадобиться перевести 20 тонн угля из карьера с Урала. Вы подумали и решили, что лучше всего проложить железную дорогу от дома до дачи и перевезти сумки на товарном поезде со специальным вагоном для сумок, который завтра будете использовать для перевозки угля...
Так примерно рассуждают те, кто пишет универсальные функции, которые "и швец, и жнец, и на дуде игрец". На самом деле, эти функции очень не удобны как при разработке, так и при использовании (Например, функция CreateFile из WinAPI32, согласитесь, что использовать этого монстра для простого открытия файла на чтение очень "весело"). Поэтому пишите простые функции, которые выполняют только одно действие, которое можно описать не более чем тремя словами (они то и составят ее название).

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

10. Не пренебрегайте использованием const
Это из разряда "предпочитайте ошибки компиляции ошибкам исполнения". Смысл этого модификатора в том, чтобы указать компилятору, что переменная не будет меняться. Поэтому, если где-то ее попытаться изменить, то компилятор тут же даст по рукам. Более того, это повышает самодокументируемость кода, так как дает некие гарантии.

11. Предпочитайте простые условия сложным
Если простейшая комбинация (i > 0) && (i < 10) читается и понимается легко, то "трёхэтажные" очень сложно разобрать. Поэтому рекомендуется их упрощать путем присваивания промежуточных значений временным переменным:
Код
const bool xValid = (x > 0) && (x < MaxX);
const bool yValid = (y > 0) && (y < MaxY);
if (xValid && yValid) {
   process(x, y);
}


12. Не забывайте комментировать код
Далеко не всегда удается писать самодокументируемый код. В этом случае следует комментировать некоторые сложные и неочевидные действия программы, когда они не выделены в отдельную функцию с говорящим названием. Например, есть некий код, который что-то считает по сложной формуле. Эта формула разбита на 10 частей. Причем, каждая часть считается, например, по ряду Тейлора, таким образом быстрого взгляда на код не достаточно, чтобы понять, что он делает (кто знает, что это такое ряд Тейлора, тот поймет). Поэтому, нужно перед каждой такой частью написать комментарий о том, что именно эта часть считает, понятным языком, в данном случае, математическим.

Не надо писать комментарии вида:
  • "подключаем заголовочный файл xxx" в строке #include <xxx>
  • "объявляем переменную x типа int" в строке int x
  • "объявляем массив y из 10 элементов типа float" в строке float y[10];
  • "реализуем функцию main" в строке int main()
Так как очевидно, что тут делается.

Итак, вот пример правильно оформленного (кроме пункта 12) кода:
Код
#include <iostream>
#include <stdexcept>

#define MY_SUM_MACRO(x,y) ((x)+(y))

class MyAbstractClass
{
public:
   enum { Value0, Value1, Value2, Value3 };
   void publicMethod();
protected:
   virtual int pureVirtualMethod() const throw() = 0;
private:
   struct PrivateData; //предварительное объявление. объявляется позже в каком-нибудь *.cpp файле
   PrivateData *pImpl_; //шаблон проектирования PIMPL (google о нем знает)
   int attr_;
   int attr2_;

   void method(int x, int y);
   void inlineMethod();
};

inline void MyAbstractClass::inlineMethod()
{
   switch(attr_) {
   case 1:
      //something
      break;
   case 2: {
            //something
      }
   }
}

int main(int argc, char *argv[])
{
   try {
      for(int i = 0; i < 10; ++i)
         func();
      int x;
      do {
         x = func2();
         if (x == -1)
            continue;
         else if (x < -1)
            break;
      } while(x);
   } catch(std::exception &e) {
      std::cerr << "Exception: " << e.what() << std::endl;
      return -1;
   } catch(...) {
      std::cerr << "Unknown exception!" << std::endl;
      return -2;
   }
   return 0;
}
Так как данный код не несет в себе хоть какой-нибудь смысловой нагрузки, то в нем нет отделения блоков кода пустыми строками. В реальном коде они очень желательны.

Если есть желание узнать больше, то рекомендую прочитать книги:
  • Г. Саттер, А. Александреску - Стандарты программирования на С++
  • С. Макконнелл - Совершенный код

Назад к FAQ

Это сообщение отредактировал(а) bsa - 26.7.2011, 11:00
PM   Вверх
andrew_121
Дата 16.8.2009, 15:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодофей
****


Профиль
Группа: Завсегдатай
Сообщений: 3448
Регистрация: 3.1.2008

Репутация: 10
Всего: 33



Цитата(bsa @  16.8.2009,  15:04 Найти цитируемый пост)
   int method1() { //все последущие идут на той же строке, что и оператор
      if (myCondition) {
         return processMyData();
      }
   }

компилятору не понравится такое smile 


--------------------
Удалил аккаунт. Прощайте!
PM MAIL   Вверх
mes
Дата 16.8.2009, 16:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(andrew_121 @  16.8.2009,  14:33 Найти цитируемый пост)
компилятору не понравится такое smile 

не поделитесь секретом, почему это вдруг не понравится ?



--------------------
PM MAIL WWW   Вверх
GoldFinch
Дата 16.8.2009, 16:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: 6
Всего: 26



перепечатка "Стандарты программирования на С++", Александреску, Саттер ?
PM MAIL ICQ   Вверх
andrew_121
Дата 16.8.2009, 16:32 (ссылка) |  (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодофей
****


Профиль
Группа: Завсегдатай
Сообщений: 3448
Регистрация: 3.1.2008

Репутация: 10
Всего: 33



Цитата(mes @  16.8.2009,  16:07 Найти цитируемый пост)
не поделитесь секретом, почему это вдруг не понравится ?

не хватает return


--------------------
Удалил аккаунт. Прощайте!
PM MAIL   Вверх
bsa
Дата 16.8.2009, 18:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Цитата(GoldFinch @ 16.8.2009,  16:17)
перепечатка "Стандарты программирования на С++", Александреску, Саттер ?

Скорей изложение своими словами. У нас же книжек никто не читает, а тут можно будет уже тыкать носом.

andrew_121
спасибо. исправил.


Замечания и пожелания приветствуются!
PM   Вверх
GoldFinch
Дата 16.8.2009, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: 6
Всего: 26



bsa, список использованной литературы бы указал
а то я те же самые слова в "стандартах" вижу, 1к1
PM MAIL ICQ   Вверх
zim22
Дата 16.8.2009, 19:06 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



я бы такой совет дал: давать имя логическому условию, а не "тупо" определять его.

Пример:
было:
Код

if (line > maxLine && line != endOfPage) {

стало:
Код

bool lineVisible = line > maxLine && line != endOfPage;
if (lineVisible) {

***
а вообще очень много советов по форматированию кода/его правильному написанию есть в книге Макконнелла "Совершенный код"

Это сообщение отредактировал(а) zim22 - 16.8.2009, 19:10


--------------------
PM MAIL   Вверх
Madonna
Дата 16.8.2009, 19:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Forbidden love...
*


Профиль
Группа: Участник
Сообщений: 107
Регистрация: 22.1.2009
Где: Москва

Репутация: нет
Всего: 4



Как насчет использования подчеркиваний в переменных?  (что мне жутко не нравится)
Когда юзается? в контролах? 
--------------------
Best regards, Madonna
PM   Вверх
bsa
Дата 16.8.2009, 19:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Цитата(GoldFinch @ 16.8.2009,  18:19)
я те же самые слова в "стандартах" вижу, 1к1

Если видишь совпадения, то приведи номера страниц. Я пролистал эту книжку и ничего подходящего не нашел.
Саттера и Александреску приводить не хочу, так как эта книга для новичков еще рановата.
PM   Вверх
Madonna
Дата 16.8.2009, 19:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Forbidden love...
*


Профиль
Группа: Участник
Сообщений: 107
Регистрация: 22.1.2009
Где: Москва

Репутация: нет
Всего: 4



и вообще насчет использования подчеркиваний в именах.
--------------------
Best regards, Madonna
PM   Вверх
bsa
Дата 16.8.2009, 19:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Цитата(Madonna @ 16.8.2009,  19:11)
Как насчет использования подчеркиваний в переменных?  (что мне жутко не нравится)
Когда юзается? в контролах?

Ты имеешь в виду приватные аттрибуты классов?
В любом случае - на вкус и цвет... Тут главное одно - постоянство. Если выбрал какой-то стандарт, то его и придерживайся.

Добавлено через 6 минут и 26 секунд
Madonna, если ты обратила внимание, в приведенном мной примере подчеркивание используется только для макроопределений. Сейчас еще добавлю класс с приватными атрибутами. Я, например, буду использовать подчеркивание только в случае невозможности применения CamelCase (разделение слов регистром). Т.е. my_super_proc смотрится гораздо лучше, чем mysuperproc. С другой стороны: My_Cool_Type - выглядит коряво, имхо.
PM   Вверх
Madonna
Дата 16.8.2009, 19:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Forbidden love...
*


Профиль
Группа: Участник
Сообщений: 107
Регистрация: 22.1.2009
Где: Москва

Репутация: нет
Всего: 4



Цитата(bsa @  16.8.2009,  17:17 Найти цитируемый пост)
Ты имеешь в виду приватные аттрибуты классов?

нет 
это понятно. В этой статье очень хорошо описано http://rsdn.ru/article/mag/200401/codestyle.XML

Меня интереуют другие случае, т.е. в сpp коде оправданы (по вашему мнению удобно использовать) подчеркивания. например some_variable (вместо как мне кажется более удобной кемел-нотации), m_variable.
 
--------------------
Best regards, Madonna
PM   Вверх
jonie
Дата 16.8.2009, 19:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 6
Всего: 118



Madonna, enum-ы часто так делают, т.к. по сути своей они определяют константы и стиль их использования НЕ EnumName::EnumValue.
Код

enum ERRORS{
 S_OK,
 E_FAIL,
...
};


я обычно обертывают такой enum в struct, чтобы было использоание в виде struct::S_OK. При этом конструктор в struct и деструктор приватные конечно 8)


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
bsa
Дата 16.8.2009, 19:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Madonna, если честно, я не люблю именования some_variable... Так как тут не очень очевидно, тип это или переменная.
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1190 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.