Comments 43
int scanCode = (lKeyData & 0xf0000) >> 16; // Bit 16-23
На самом деле, в этой строке, судя по комментарию, две ошибки :)
Видимо да. Кстати, это не единственно место с неудачным оператором &&. Вот этот пример в статью не вошёл, но он тоже прекрасен:
#define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */
#define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */
... и так далее
void QAudioDeviceInfoInternal::updateLists()
{
...
DWORD fmt;
...
if((fmt && WAVE_FORMAT_1M08)
|| (fmt && WAVE_FORMAT_1S08)
|| (fmt && WAVE_FORMAT_2M08)
|| (fmt && WAVE_FORMAT_2S08)
|| (fmt && WAVE_FORMAT_4M08)
|| (fmt && WAVE_FORMAT_4S08)
#ifndef Q_OS_WINCE
|| (fmt && WAVE_FORMAT_48M08)
|| (fmt && WAVE_FORMAT_48S08)
|| (fmt && WAVE_FORMAT_96M08)
|| (fmt && WAVE_FORMAT_96S08)
#endif
)
...
}
А можно узнать, были ли разработчики Qt уведомлены о найденных ошибках?
Нет. Я имею на руках здоровенный отчет, который нужно внимательно исследовать. Я отправлю разработчикам QT ссылку на перевод этой статьи, когда он появится. Если их заинтересует эта заметка, они сами смогут проверить библиотеку и исправить то, что посчитают дефектами.
Кстати, информация уже сама собой расползается: Article about Qt bugs found with static analyzer “PVS-Studio”
> Как уменьшить вероятность ошибки на этапе написания кода
Не юзать сраный Си++)
Не юзать сраный Си++)
Есть довольно дорогой способ проверки качества кода — заставлять одного (лучше более опытного, но не обязательно) программиста смотреть правки другого и давать замечания. Для того, чтобы замечания были обоснованными — также необходимо наличие некоторого корпоративного свода правил кодирования.
Да, слишком дорого. Поэтому и появился компромисс — статические анализаторы исходного кода. Ими может воспользоваться сам программист. А может и тот, кто просматривает чужой код. Он экономит своё время, читая не весь код коллег, а только наиболее подозрительные места.
P.S. Просто так, не в тему. Порадовал юмор разработчиков QT. Им было нужно какое-то магическое значение указателя для внутренних нужд. Они выбрали это:
notified.insert( (void*)dns, (void*)42 );
notified.insert( (void*)dns, (void*)42 );
Про таблицы не согласен, затем плодить лишние массивы, если можно красиво все оформить через switch? Главное, чтобы в нем условия были отсортированы, а не шли вперемешку.
Таблицы еще и оверхед вносят, хотя если свитч грозится быть более, чем из 10 элементов, то лучше табличку сделать, а там поиск по ключам оптимизировать, то есть упорядочить их и юзать бинарный поиск вместо линейного как в свичах.
Вспоминаются исходники LastFM, файл SideBarView.cpp, где длиннющий метод с множеством case-ов.
Ищится по:
Ищится по:
//TODO Woah! This became huge. DRY!
//REFACTOR IMMEDIATELY!
И, кстати, не факт, что так будет быстрее. Если разные ветви выполняются с разной частотой, то бинарный поиск может оказаться хуже, чем если наиболее часто используемые проверить сначала, а потом всё остальное. Но тут подводный камешек, что C++ может переставить порядок по своему усмотрению.
Да, согласен. Часто это тоже будет хорошим вариантом. Впрочем от забытых break; это не спасает. Надо было ведь такой синтаксис придумать для switch…
Длинный-предлинный switch(). И, естественно, имеется забытый оператор «break».
Lookup table (BTW, откуда термин «табличный метод»?) я тоже люблю. Но потерянные break ИМХО больше от неумения писать на C++. Потому как эталонный switch выглядит вот так:
switch( condition )
{
break; case 1:
Foo();
break; case 2:
Bar();
break; case 3:
Baz();
break; default:
ENSURE( false );
}
Ну а те кто честно ручками ставят break после каждого case и так же ручками его там зыбывают… Каждый сам кузнец своего счастья, не?
В книге Code Complete таблицы называются Direct Access Tables (18.2.) и Indexed Access Tables (18.3.) Общим названием для них Стив использует lookup-tables. Наверное название «табличный метод» растёт оттуда.
Не знал о таком приеме.
Ситуация точно такая же, как с if (0 == x) — надежно, но неестественно смотрится :)
Ситуация точно такая же, как с if (0 == x) — надежно, но неестественно смотрится :)
Ну мы чай не философы на художественной выставке. Естественно смотрится, неестественно смотрится… Код вообще такая штука, которая не очень естественно смотрится :). Главное — чтобы задачи решались и метрики соблюдались. А что школьникам непонятно будет — так на то они и школьники. Деятельность физиков-ядерщиков или микробиологов им тоже непонятна. ИМХО, образование отдельно, промышленное применение — отдельно.
Есть и другое мнение — «программы пишут не для компьютеров, а для людей» :)
Компилятор-то код худо-бедно сожрет, а вот если творение предыдущего программиста без поллитры не поймешь, то печально… Я как-то переписал большой кусок кода на C# только потому, что он был написан в паскалевских традициях и развивать его было мучительно. Впрочем, этот кусок от переписывания сократился раза в два и чуток ускорился.
Компилятор-то код худо-бедно сожрет, а вот если творение предыдущего программиста без поллитры не поймешь, то печально… Я как-то переписал большой кусок кода на C# только потому, что он был написан в паскалевских традициях и развивать его было мучительно. Впрочем, этот кусок от переписывания сократился раза в два и чуток ускорился.
Надо бы упомянуть о «несправедливости». Не знаю, правда, как компилятор VisualC++, а GCC/G++ давно умеет сворачивать switch в табличку, если это целесообразно. Конечно, табличка предполагает последовательные значения — ибо просто массив адресов, без ключей. Но для большинства enum'ов — как раз тоЮ что надо.
Пример с «if (q && (q->getQueryName() != _T(»BooleanQuery")" не очень убедителен, так как не очень понятно, что за сущность «q», что возвращает getQueryName и нет ли в округе каких-нибудь перегруженных операторов, меняющих явно видимую логику.
А вот расскажите мне, я удивляюсь и не понимаю, как с такими ошибками (функция equals явно что-то часто сравнивает, неинициализированные переменные, неправильная функция декодирования какого-то сообщения и т.д.) это вообще работает, почему?)) И ведь эта библиотека используется во множестве проектов.
Я сам в шоке! :)
Причем в постоянном. Вот представьте, добавляю новое правило, что нет смысла в сравнениях вида if (pointer != «ABCD»). Кажется, что и не найдется то ничего. Разве только лабы у студентов проверять. А оно как полезет в разных проектах из разных щелей… Волосы дыбом. Ну что-то в таком духе:
Причем в постоянном. Вот представьте, добавляю новое правило, что нет смысла в сравнениях вида if (pointer != «ABCD»). Кажется, что и не найдется то ничего. Разве только лабы у студентов проверять. А оно как полезет в разных проектах из разных щелей… Волосы дыбом. Ну что-то в таком духе:
#define MP4_AUDIO_TRACK_TYPE "soun"
#define MP4_VIDEO_TRACK_TYPE "vide"
...
const char* normType = MP4Track::NormalizeTrackType(type);
...
if (normType == MP4_AUDIO_TRACK_TYPE) {
if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
continue;
}
} else if (normType == MP4_VIDEO_TRACK_TYPE) {
if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
continue;
}
}
Все очень просто. Есть часто используеме модули и ветки кода. А есть редкоиспользуемы. Видимо, это ошибки в крайне редко используемой функциональности. Или вообще в коде, который не используется но остался «со старых времен». Плюс ряд ошибок программа может «проглотить» — тоесть если, условно, алгоритм выбора оптимального кодека работает неверно — кодек все равно будет выбран. Просто не тот :).
Прочитал про табличные функции. Не знал что это так называется, но сам давным-давно к этому пришел.
такое ощущение, что почти все ошибки в цпп — следствие невнимательного копипаста…
Скажите, как вы натравили PVS-Studio на исходники Qt? Когда-то выходила бесплатная редакция PVS-Studio, хотел с ней такое попробовать, но не вышло, т.к. Qt генерит какие-то кривые солюшены Visual Studio для своих исходников…
как-то совсем «детские» ошибки. после этого немного страшню юзать Qt
Sign up to leave a comment.
Как уменьшить вероятность ошибки на этапе написания кода. Заметка N3