Как уменьшить вероятность ошибкина этапе написания кода. Заметка N                                 N2.Автор: Андрей Карпов...
Рисунок 1 - Операции языка Си/Си++, в порядке снижения приоритетаОбратите внимание, что операция ?: имеет более низкий при...
int Z = X + (A == B ? 1 : 2);Первая мысль – так ведь надо знать приоритет операций. А программисты их и знают, но уж очень...
void CustomFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {    ...    int edge_height = titlebar_bottom->height...
Конечно, и с этим проблем нет, но создание ссылки на A или B без оператора ?: будет гораздомногословней:MyObject *tmpPtr;I...
не только защитит от потенциальных ошибок, но и сделает код более легко читаемым для другихразработчиков.Ошибки с путанице...
}Ну и еще один пример из Chromium:V564 The & operator is applied to bool type value. Youve probably forgotten to include p...
Программист, который в будущем будет читать ваш код со скобками, только скажет спасибо заэто.
Upcoming SlideShare
Loading in …5
×

Как уменьшить вероятность ошибки на этапе написания кода. Заметка N2.

255 views

Published on

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

Published in: Technology, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
255
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Как уменьшить вероятность ошибки на этапе написания кода. Заметка N2.

  1. 1. Как уменьшить вероятность ошибкина этапе написания кода. Заметка N N2.Автор: Андрей КарповДата: 29.03.2011АннотацияЭто вторая статья о том, как можно избежать ряда ошибок еще на этапе написания кода. Впредыдущей заметке уже упоминался совет избегать множества вычислений в одном выражении.Однако, этот вопрос требует более пристального внимания. Рассмотрим опасность сложныхусловий, и как можно предупредить многие логические ошибки.ВведениеС предыдущей заметкой можно познакомиться здесь. В этот раз примеры ошибок будут взяты из тразличных известных проектов, чтобы подчеркнуть их распространенность Ошибки, которые распространенность.будут продемонстрированы были найдены мной с помощью анализатора PVS-Studio за продемонстрированы,относительно большой промежуток времени. Практически про все я писал разработчикам ипоэтому можно надеяться, что они поправлены в новых редакциях кода. Это я пишу во введении,потому что после статей мне всегда приходят письма с просьбой "напишите про найденные вамиошибки разработчикам проекта".1. Не используйте тернарн тернарную операцию ?: в составных выраженияхТернарная условная операция записывается в языке Си/Си++ с помощью оператора ?:. Операция, Си++возвращающая свой второй или третий операнд в зависимости от значения логическоговыражения, заданного первым операндом. Пример:int minValue = A < B ? A : B;Тернарная операция имеет очень низкий приоритет (см. таблицу). Про это часто забывают иименно из-за этого тернарная операция крайне опасна. за
  2. 2. Рисунок 1 - Операции языка Си/Си++, в порядке снижения приоритетаОбратите внимание, что операция ?: имеет более низкий приоритет, чем сложение, умножение,оператора побитового ИЛИ и так далее. Рассмотрим код:int Z = X + (A == B) ? 1 : 2;Этот код работает не так, как может показаться на первый взгляд. Программист, скорее всего,хотел сложить значение X с числом 1 или с числом 2, в зависимости от условия (A == B). Но насамом деле условием является выражение "X + (A == B)". Фактически, здесь написано:int Z = (X + (A == B)) ? 1 : 2;А хотелось:
  3. 3. int Z = X + (A == B ? 1 : 2);Первая мысль – так ведь надо знать приоритет операций. А программисты их и знают, но уж оченьковарна эта тернарная операция! Ошибки с ней допускают не только новички, но и матёрыепрограммисты. Её нередко можно встретить даже в самом качественном коде. Вот парапримеров.V502 Perhaps the ?: operator works in a different way than it was expected. The ?: operator has alower priority than the * operator. physics dgminkowskiconv.cpp 1061dgInt32 CalculateConvexShapeIntersection (...){ ... den = dgFloat32 (1.0e-24f) * (den > dgFloat32 (0.0f)) ? dgFloat32 (1.0f) : dgFloat32 (-1.0f); ...}V502 Perhaps the ?: operator works in a different way than it was expected. The ?: operator has alower priority than the - operator. views custom_frame_view.cc 400static const int kClientEdgeThickness;int height() const;bool ShouldShowClientEdge() const;
  4. 4. void CustomFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) { ... int edge_height = titlebar_bottom->height() - ShouldShowClientEdge() ? kClientEdgeThickness : 0; ...}V502 Perhaps the ?: operator works in a different way than it was expected. The ?: operator has alower priority than the | operator. vm vm_file_win.c 393#define FILE_ATTRIBUTE_NORMAL 0x00000080#define FILE_FLAG_NO_BUFFERING 0x20000000vm_file* vm_file_fopen(...){ ... mds[3] = FILE_ATTRIBUTE_NORMAL | (islog == 0) ? 0 : FILE_FLAG_NO_BUFFERING; ...}Как видите, ошибки данного типа заслуживают внимания. И я не случайно выделил их описание вотдельный пункт. Они весьма и весьма распространены. Можно привести другие примеры, но всеони однотипны.Избежать подобных ошибок можно, если не стремиться поместить несколько операций в однустроку кода. А если и помещать, то не жадничать поставить дополнительные скобки. Про скобкимы поговорим ниже. Сейчас попробуем просто предотвратить потенциальные ошибки прииспользовании ?:.Конечно оператор ?: является синтаксическим сахаром и его практически всегда можно заменитьна if. К редким исключениям относится такие задачи, как инициализация ссылки:MyObject &ref = X ? A : B;
  5. 5. Конечно, и с этим проблем нет, но создание ссылки на A или B без оператора ?: будет гораздомногословней:MyObject *tmpPtr;If (X) tmpPtr = &A;else tmpPtr = &B;MyObject &ref = *tmpPtr;Итак, отказываться от оператора ?: не рационально. Но и ошибиться с ним просто. Поэтому личноя выработал для себя следующее правило. Результат ?: должен сразу куда-то помещаться и несочетаться с другими действиями. То есть слева от условия оператора ?: должна стоять операцияприсваивания. Вернемся к первоначальному примеру:int Z = X + (A == B) ? 1 : 2;Я предлагаю писать так:int Z = X;Z += A == B ? 1 : 2;В случае примера, относящегося к IPP Samples, я бы написал так:mds[3] = FILE_ATTRIBUTE_NORMAL;mds[3] |= (islog == 0) ? 0 : FILE_FLAG_NO_BUFFERING;С рекомендацией можно не согласиться. Не буду её отстаивать. Например, мне не очень нравится,что вместо одной строки мы получаем две или более. Неплохой альтернативой может бытьобязательное взятие оператора ?: в скобки. Я ставлю основной задачей показать паттерныошибок. Выбор паттерна защиты от ошибок зависит от предпочтений программиста.2. Не стесняйтесь использовать скобкиПочему-то так повелось, что использование лишних скобок при программировании на Си/Си++считается неким постыдным действием. Возможно, это идёт от того, что вопрос про приоритетопераций очень любят задавать на собеседовании. И у человека подсознательно откладываетсястремление всегда максимально использовать механизм приоритетов. Ведь если он поставитлишние скобки, то вдруг кто-то подумает что он новичок, а не истинный джедай.Я даже встречал на просторах интернета обсуждение, где человек категорично утверждал, чтоиспользование лишних скобок - это плохой тон. А если человек не уверен как будет вычисленовыражение, то ему надо учиться, а не программы писать. К сожалению, не смог найти этудискуссию, но я не разделяю подобные точки зрения. Знать приоритеты, конечно, надо, но если ввыражении используются разнородные операции, то лучше подстраховывать себя скобками. Это
  6. 6. не только защитит от потенциальных ошибок, но и сделает код более легко читаемым для другихразработчиков.Ошибки с путаницей приоритетов также возникают не только у новичков, но и у профессионалов.При этом выражение не обязательно должно быть сильно запутанным и длинным. Ошибку можнодопустить и в относительно простых выражениях. Рассмотрим некоторые примеры.V564 The & operator is applied to bool type value. Youve probably forgotten to include parentheses orintended to use the && operator. game g_client.c 1534#define SVF_CASTAI 0x00000010char *ClientConnect(...) { ... if ( !ent->r.svFlags & SVF_CASTAI ) { ...}V564 The & operator is applied to bool type value. Youve probably forgotten to include parentheses orintended to use the && operator. dosbox sdlmain.cpp 519static SDL_Surface * GFX_SetupSurfaceScaled(Bit32u sdl_flags, Bit32u bpp) { ... if (!sdl.blit.surface || (!sdl.blit.surface->flags&SDL_HWSURFACE)) { ...
  7. 7. }Ну и еще один пример из Chromium:V564 The & operator is applied to bool type value. Youve probably forgotten to include parentheses orintended to use the && operator. base platform_file_win.cc 216#define FILE_ATTRIBUTE_DIRECTORY 0x00000010bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { ... info->is_directory = file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0; ...}Выражения просты. Разработчики молодцы. А ошибки всё равно есть. Так что использованиескобок в скользких местах лишним не будет.Наверное, стоит поступать так. Если операции просты и привычны, то дополнительные скобки ненужны. Примеры:if (A == B && X != Y)if (A - B < Foo() * 2)А вот если используются более редкие операторы (~, ^, &, |, <<, >>, ?:), то явные скобки неповредят. Это и упростит чтение кода и защит от потенциальной ошибки. Примеры:If ( ! (A & B))x = A | B | (z < 1 ? 2 : 3);Не стесняться использовать скобки при использовании редких операций поможет и длярассмотренного ранее оператора "?:". Как именно лучше поступить с "?:" - дело вкуса. Мне болеенравится вариант с упрощением.ЗаключениеПишите простой и понятный код. Разбивая длинные и сложные выражения на несколько строк, выполучаете более длинный код. Но такой код бывает намного проще понять и прочитать. В немменьше вероятность допустить ошибку. Не бойтесь завести лишнюю переменную. Компиляторотлично всё оптимизирует.Не жадничайте на скобках в выражениях, где используются редкие операторы или гдесмешиваются битовые и логические операции.
  8. 8. Программист, который в будущем будет читать ваш код со скобками, только скажет спасибо заэто.

×