1

Тема: Поради зі стилю програмування на C++

http://uk.wikibooks.org/wiki/%D0%9D%D0% … 8F_C%2B%2B
Ласкаво прошу до обговорення, критики і коментарів.

Подякували: Очі.завидющі, Chemist-i, leofun014

2

Re: Поради зі стилю програмування на C++

Мені сподобалася стаття, але хочеться більше почути ще про чисті ся. Особливо про ті нові божевільні можливості, що дозволяють за допомогою препроцесора перезавантажувати функції та ін.

3 Востаннє редагувалося Очі.завидющі (02.05.2013 00:16:58)

Re: Поради зі стилю програмування на C++

40. До файлу заголовків треба додати захист включення.

Ця інформація вже застаріла, бо є

#pragma once

Усі мейнстріймові компілери підтримують цю опцію.

І напишіть ще про нічні жахи програмістів - мадярська нотація для найменувань змінних. І чому заголовкові файли вінди використовують чудернацькі типи даних? (Бо вона писалася до стандартизації сєй)

4

Re: Поради зі стилю програмування на C++

Очі.завидющі написав:

Мені сподобалася стаття, але хочеться більше почути ще про чисті ся. Особливо про ті нові божевільні можливості, що дозволяють за допомогою препроцесора перезавантажувати функції та ін.

Ви про _Generic? Так вам ніхто не заважає самостійно розкопати тему і створити гілку. Залюбки почитаю, може, й сам долучуся до обговорення. ISO/IEC 9899:2011 в поміч.

Очі.завидющі написав:

40. До файлу заголовків треба додати захист включення.

Ця інформація вже застаріла, бо є

#pragma once

Усі мейнстріймові компілери підтримують цю опцію.

Директива #pragma за стандартом залежить від реалізації. Тобто якщо це буде стандартизовано, то іншою директивою. До речі, ще існує #import... який також не стандартизований, але деінде використовується.

Очі.завидющі написав:

І напишіть ще про нічні жахи програмістів - мадярська нотація для найменувань змінних. І чому заголовкові файли вінди використовують чудернацькі типи даних? (Бо вона писалася до стандартизації сєй)

Цей текст не про криворуких програмерів, а про те, як самому не бути криворуким :)

Подякували: Очі.завидющі, leofun013

5

Re: Поради зі стилю програмування на C++

Файна стаття, дякую. :)

Та кілька монеток вставлю:

9. Скорочення в іменах не треба записувати великими літерами [4].

Отут не погоджуся. Якщо код попаде до іншого програміста, є ризик, що він сплутає аббревіатуру зі скороченням всередині назви.

11. В приватні змінні класів слід додавати підкреслення наприкінці.

Якби стаття присвячувалася Пітону, я б зрозумів таке. Але який сенс на хрестах? Контроль доступу до полів визначається на етапі компіляції, і спроба прямого втручання у приват ззовні викличе бугурт компілятора.

void setDepth (int depth)
  {
    depth_ = depth;
  }

Якщо недоля спричинила нестачу уяви, то просто додайте води this.

17. Треба використовувати терміни get та set, коли забезпечується безпосередній доступ до атрибуту.-

Плюс у карму. Порушення цього положення викликало у мене певний ступор під час переходу від qt до fltk, а потім до wxWidgets. :)

18. Термін compute може використовуватися в методах, що щось обчислюють.

calcSmth, countSmth, processSmth - залежно, що саме рахує і яким чином.

Слід надавати перевагу американському initialize перед англійським initialise. Слід уникати скорочення init.

Знову я єретик-ортодокс, по ходу... :)

34. Файлам заголовків слід давати розширння .h (бажано) чи .hpp. Сирцевим файлам слід давати розширення .c++(рекомендовано), .C, .cc чи .cpp.

Поки я пишу під віндою, такий стиль (крім .c++ - лолват?) прийнятний. А під іксами ліпше брати .hxx, .cxx, які умовно покажуть, що програма написанна саме для іксових систем.

36. Реалізації слід повністю розміщувати в сирцевих файлах.

А як же inline-методи? :) Якщо метод описати прямо у заголовку, він стає inline автоматично, і якщо там щось просте типу setMyField(F* f){field = f;}, то який сенс засмічувати код сирця такими прищами?

38. Треба уникати особливих символів, таких, як TAB та розрив сторінки.

Згоден, крім табуляції: її розмір у пробілах дозволяють регулювати чи не всі нормальні редактори.

46. Змінні слід ініціалізувати при оголошенні.

Зайва операція - зайві проблеми, особливо якщо не є необхідною.

53. Неявну перевірку на 0 слід вживати тільки з булівськими змінними і вказівниками.

Знову падіння продуктивності. Не так уже й складно зрозуміти, що предикат у блоці if - це неявний bool. Плюс граблі, якщо забути "==" замість "="... :)

57. Можна уникати циклів do-while.

Імго, кожній конструкції - своя сфера використання.

58. Слід уникати break та continue.
Форма for(;;) не дуже читана, і не очевидно, що це дійсно нескінчений цикл.

о_О?

____

Якось так. :)

6

Re: Поради зі стилю програмування на C++

Bartash написав:

9. Скорочення в іменах не треба записувати великими літерами [4].

Отут не погоджуся. Якщо код попаде до іншого програміста, є ризик, що він сплутає аббревіатуру зі скороченням всередині назви.

Якщо є такий ризик - то треба користуватися п. 28

Bartash написав:

34. Файлам заголовків слід давати розширння .h (бажано) чи .hpp. Сирцевим файлам слід давати розширення .c++(рекомендовано), .C, .cc чи .cpp.

Поки я пишу під віндою, такий стиль (крім .c++ - лолват?) прийнятний. А під іксами ліпше брати .hxx, .cxx, які умовно покажуть, що програма написанна саме для іксових систем.

Як на мене, безглуздо вказувати розширенням цільову систему. Так ми до .hbsd і .cppwin6 дійдемо.

Bartash написав:

36. Реалізації слід повністю розміщувати в сирцевих файлах.

А як же inline-методи? :) Якщо метод описати прямо у заголовку, він стає inline автоматично, і якщо там щось просте типу setMyField(F* f){field = f;}, то який сенс засмічувати код сирця такими прищами?

Класика. Перший програміст пише очевидний інлайн-сеттер. Другий додає всередину count++. А третій довго шукає в файлі імплементації, чому це раптом змінюються дві змінні, якщо нічого не чіпалося.

Bartash написав:

38. Треба уникати особливих символів, таких, як TAB та розрив сторінки.

Згоден, крім табуляції: її розмір у пробілах дозволяють регулювати чи не всі нормальні редактори.

Так, про TAB - порада для досить специфічних ситуацій; але якщо пишете під консоль - краще не вживати і таби, невідомо, через який ssh доведеться його переглядати :)

Bartash написав:

46. Змінні слід ініціалізувати при оголошенні.

Зайва операція - зайві проблеми, особливо якщо не є необхідною.

Ну, там сказано, коли не треба. І взагалі п.54.

Bartash написав:

53. Неявну перевірку на 0 слід вживати тільки з булівськими змінними і вказівниками.

Знову падіння продуктивності. Не так уже й складно зрозуміти, що предикат у блоці if - це неявний bool. Плюс граблі, якщо забути "==" замість "="... :)

Вибачте, коли я народився, там ще було можливе зниження продуктивності, але коли вперше побачив комп'ютер, оптимізатори вже були розроблені і поширені. А якщо змінюється математика із зсувом з 0 на 1 - то проблеми точно будуть...

Bartash написав:

57. Можна уникати циклів do-while.

Імго, кожній конструкції - своя сфера використання.

Тому не слід, а можна.

Bartash написав:

60. Форма for(;;) не дуже читана, і не очевидно, що це дійсно нескінчений цикл.

о_О?

Ну, for(;;) можна перекласти як "для Ктулху" :), що не означає нескінченості. А от "поки правда" - трохи краще.

7 Востаннє редагувалося User 298 (02.05.2013 11:16:56)

Re: Поради зі стилю програмування на C++

koala написав:

Ну, for(;;) можна перекласти як "для Ктулху" :) , що не означає нескінченості. А от "поки правда" - трохи краще.

А якщо цикл написаний якраз особисто для Ктулху з метою створення якогось тайм-аута/затримки?

for(;;)
{
    Sleep(n);
    if( wakeUpDude())
        break;
}

:)

8

Re: Поради зі стилю програмування на C++

Bartash написав:
koala написав:

Ну, for(;;) можна перекласти як "для Ктулху" :) , що не означає нескінченості. А от "поки правда" - трохи краще.

А якщо цикл написаний якраз особисто для Ктулху з метою створення якогось тайм-аута/затримки?

for(;;)
{
    Sleep(n);
    if( wakeUpDude())
        break;
}

:)

Нащо так просто? Давайте вже

void waitForWakeUp()
{
  Sleep();
  if(wakeUpDude())return;
  else waitForWakeUp();
}

якщо вже легких шляхів не шукати...

Прихований текст
do {
  Sleep(n);
}while(!wakeUpDude())

9

Re: Поради зі стилю програмування на C++

Як на мене, безглуздо вказувати розширенням цільову систему. Так ми до .hbsd і .cppwin6 дійдемо.

Не дійдемо. Пригадую, що читав про загальноприйнятість .*xx назв для систем сімейства Unix серед цпп-розробників.

Класика. Перший програміст пише очевидний інлайн-сеттер. Другий додає всередину count++. А третій довго шукає в файлі імплементації, чому це раптом змінюються дві змінні, якщо нічого не чіпалося.

За таку класику халтуру треба молотком відбивати пальці. І Кент Бек буде першим у черзі на отримання молотка для цього. :)

Так, про TAB - порада для досить специфічних ситуацій; але якщо пишете під консоль - краще не вживати і таби, невідомо, через який ssh доведеться його переглядати :)

Ну і яка ймовірність того, що ви попадете на систему, де не буде навіть vim'а чи ще чогось езотеричнішого? ;)

Вибачте, коли я народився, там ще було можливе зниження продуктивності, але коли вперше побачив комп'ютер, оптимізатори вже були розроблені і поширені. А якщо змінюється математика із зсувом з 0 на 1 - то проблеми точно будуть...

Довелося мені у недалекому минулому ваяти синтаксичний аналізатор текстових файлів. Мушу сказати, що поняття продуктивності нікуди не пропадало, особливо коли брався набір із порядка 1000 файлів по кількасот кб кожен.
Оптимізатор - теж дуже умовна річ. Можливо, програміст хотів ув одному моменті робити більше речей прямо у регістрах процесора, а оптимізатор вирішить по-своєму, бо є універсальним, а все універсальне - це лише матсподівання...

Bartash написав:

57. Можна уникати циклів do-while.
Імго, кожній конструкції - своя сфера використання.

Тому не слід, а можна.

Якось я пропустив період, коли do-while слід було використовувати повсюдно. :D

do {
  Sleep(n);
}while(!wakeUpDude())

Best. Тут визнаю переваги do-while над for(;;) для даної задачі. :D

10

Re: Поради зі стилю програмування на C++

Bartash написав:

Класика. Перший програміст пише очевидний інлайн-сеттер. Другий додає всередину count++. А третій довго шукає в файлі імплементації, чому це раптом змінюються дві змінні, якщо нічого не чіпалося.

За таку класику халтуру треба молотком відбивати пальці. І Кент Бек буде першим у черзі на отримання молотка для цього. :)

Кому саме з трьох?

Bartash написав:

Ну і яка ймовірність того, що ви попадете на систему, де не буде навіть vim'а чи ще чогось езотеричнішого? ;)

Поки що - відмінна від нуля. Хоча ймовірність ще й писати під таку систему, і налагоджувати безпосередньо на ній...

Bartash написав:

Оптимізатор - теж дуже умовна річ. Можливо, програміст хотів ув одному моменті робити більше речей прямо у регістрах процесора, а оптимізатор вирішить по-своєму, бо є універсальним, а все універсальне - це лише матсподівання...

Якщо програміст хоче працювати безпосередньо з процесором, то не користується C++.

Bartash написав:

Якось я пропустив період, коли do-while слід було використовувати повсюдно. :D

Ступінь важливості порад.
Поради зґруповані за темами і кожна порада пронумерована для полегшення посилань на них.
В цих настановах слова треба, слід та може мають особливе значення. Треба означає, що поради треба дотримуватися, слід - наполеглива рекомендація, а може - загальна настанова.

Це все ще нічого, я тут ось таке наперекладав (від того ж автора..): http://uk.wikibooks.org/wiki/%D0%9D%D0% … 8F_C%2B%2B

11

Re: Поради зі стилю програмування на C++

Стосовно оптимізації: спробуйте скопмілювати

  clock_t start=clock();
  int t=1;
  for(int i=0;i<1000000;i++)t=t*2+1;
  clock_t time1=clock()-start;
  t=1;
  for(int i=0;i<1000000;i++)t=(t<<1)|1;
  clock_t time2=clock()-time1;
  cout << "operation 1:" << time1 <<" operation 2:" <<time2;

і відпишіться по результатах...

12

Re: Поради зі стилю програмування на C++

Кому саме з трьох?

Другому. За інкремент у недозволених місцях.

Поки що - відмінна від нуля. Хоча ймовірність ще й писати під таку систему, і налагоджувати безпосередньо на ній...

От коли доведеться ваяти під OS 390 чи ще щось суворіше, то тоді ок. А поки що - шиндоус, нікси, цеброїди та яблука. :)

Якщо програміст хоче працювати безпосередньо з процесором, то не користується C++.

Приклад був про "пропозицію" register.

Це все ще нічого, я тут ось таке наперекладав (від того ж автора..):

То пізніше почитаю, бо флудозапас мій вичерпується потроху, рівно як і вільний час. :)

13

Re: Поради зі стилю програмування на C++

По коду:

Замінив cout на printf
#include <cstdio>
#include <ctime>

int main()
{
    clock_t start = clock();
    
    int t = 1;
    
    for(int i = 0; i<1000000; i++)
        t = t*2 + 1;
    clock_t time1=clock()-start;
    t = 1;
    
    for(int i = 0; i<1000000; i++)
        t = (t<<1)|1;
    clock_t time2 = clock() - time1;
    printf("operation 1: %u\noperation 2: %u\n", time1, time2);
    
    return 0;
}
Результат

http://osidok.pp.ua/images/2013/05/02/test.png

14

Re: Поради зі стилю програмування на C++

Не хочете результат прокоментувати? Чому множення і додавання в рази швидші за зсув і побітове АБО?

15 Востаннє редагувалося Очі.завидющі (03.05.2013 09:42:43)

Re: Поради зі стилю програмування на C++

Не хочете результат прокоментувати? Чому множення і додавання в рази швидші за зсув і побітове АБО?

Тут двояка тема - з одного боку дійсно воно швидше, бо використовуються команди shl/shr, а з іншого якщо компілятору так писати, то чи не леше принаймні частину проекта написати мовою асемблера і злінкувати усе разом або ж інлайн-ассемблером скористатись?

P.S.
Високорівневі кодери будуть гадати на кавовій гущи, а повний опис причини швидкості того коду можливо побачити лише порівнявши згенеровані асм лістинги декількох мейнстріймових компіляторів із різними опціями.

16

Re: Поради зі стилю програмування на C++

От у тому й проблема - ці дрібні "оптимізації" на кшталт заміни *2 на <<1 чи пропускання ==0 ніц не оптимізують (бо вбудований оптимізатор все одно зробить краще), а заплутати при читанні програми людиною можуть. Хочете реальної оптимізації на рівні машинних кодів - пишіть на асемблері, а пишете на мові високого рівня - залиште оптимізацію компілятору.

17

Re: Поради зі стилю програмування на C++

ці дрібні "оптимізації" на кшталт заміни *2 на <<1 чи пропускання ==0 ніц не оптимізують

Найдурніше те, що вони оптимізують, тому на джерельні коди С для 8051 процесора без сліз не глянеш. Хоча доки ви не майните біткойни/ламаєте хеш/створюєте 3д гру воно несуттєво впливає на результат. Принаймні VC++ 2010 прості як двері. Мабуть я створю статтю з порівнянням оптимізацій різних алгоритмів/різних процесорів, бо вмію реверс інженерити.

18

Re: Поради зі стилю програмування на C++

А можна не грозитися, а навести конкретний приклад? Я ж вам навів.

19

Re: Поради зі стилю програмування на C++

Приклад 1
Чому в дупу п'яний кодер, що знає лише одну двадцяту частину машинних команд, створює за один прохід асемблерний лістинг оптимальніший за багатопрохідні вумні компілятори С++ для процесорів архітектури х86?
Відповідь полягає в регістровій архітектурі х86 процесора. Найшвидше процесор робить операції саме із регістрами. Регістрів загального значення небагато (EAX, EBX, ECX, EDX, EDI, ESI) і на всі змінні їх не вистачає. До того ж регістри EDI, ESI, ECX використовуються для копіювання/порівняння, тому компілятори часто їх не використовують. Команда ділення/множення впливає на регістри EAX, EDX. Тому в більшості випадків компілятор зберігає змінні не у регістрах, а в пам'яті, іноді копіюючи їх у регістри для різних операцій і результат.. записує знову в па'мять. Тобто компіляторний лістинг буде повільнішим відсотків на 100% за асемблерний лістинг старого алконафта тільки через відсутність нормального розподілу регістрів. Людина має інтуїцію і вміє розкладувати пас'янcи краще за комп'ютер. Але це стосується лише CISC архітектури й х86 зокрема.
Стосовно оптимізації для 8051 архітектури напишу трохи згодом.

20

Re: Поради зі стилю програмування на C++

Давайте трохи визначимося із твердженнями, навколо яких іде суперечка. Я стверджую, що "звичайний" C/C++-код, опрацьований оптимізатором, в загальному випадку створює байт-код не гірший за "оптимізований" на рівні дрібних фокусів в програмі (на кшталт опускання !=0, заміни ...==0 на !..., заміни *4 на <<2 і т.д.), але значно краще читається. Що намагаєтеся довести ви? Що асемблер дає кращий код, ніж C++? Яким чином це стосується мого твердження?
Ну а "приклад" взагалі недоречний, бо його не можна відтворити. На відміну від мого.