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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Во всём виноват компилятор 
:(
    Опции темы
Thunderbolt
Дата 10.9.2012, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


DevRel
*


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

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



Многие программисты очень любят обвинять компилятор в различных ошибках. Поговорим немного об этом.

А был ли мальчик?

Когда программист говорит, что причиной ошибки является компилятор, в 99% случаев, он врёт. Когда начинается детальное изучение проблемы, то, как правило, причины такие:
  • выход за границы массива;
  • неинициализированная переменная;
  • опечатка;
  • ошибка синхронизации в параллельной программе;
  • использование не volatile переменной, там, где надо;
  • написан код, приводящий к неопределённому поведению;
  • и так далее.

Многие проходили через исправление подобных ошибок. Много читали о них. Однако это не мешает вновь и вновь обвинять в смертных грехах компилятор. Каждый раз, кажется, что вот теперь-то виноват именно он.

Конечно, компилятор тоже может содержать ошибки. Но если вы не используете экзотический компилятор для микроконтроллера, то такая вероятность очень низкая. За многие годы работы с Visual C++ я только один раз видел, когда он сгенерировал некорректный ассемблерный код.

Небольшая рекомендация

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

Что побудило написать меня эту заметку

Сегодня меня крайне позабавил фрагмент кода из проекта ffdshow. Вот он:

Код
TprintPrefs::TprintPrefs(IffdshowBase *Ideci,
                         const TfontSettings *IfontSettings)
{
  memset(this, 0, sizeof(this)); // This doesn't seem to
                                 // help after optimization.
  dx = dy = 0;
  isOSD = false;
  xpos = ypos = 0;
  align = 0;
  linespacing = 0;
  sizeDx = 0;
  sizeDy = 0;
  ...
}


Глядя на комментарий, я представляю, как негодовал программист. Ах, этот несносный компилятор! В Debug-версии все переменные равны 0. В release-версии из-за неработающей оптимизации, в них мусор. Это безобразие! Плохой, плохой компилятор!

Поругав компилятор, программист оставляет обвиняющий комментарий. И пишет ниже код, который по отдельности обнуляет каждый член класса. Победа мужества над силами зла.

И ведь главное, этот человек останется уверенным, что встречал баг в компиляторе. И будет рассказывать, как из-за него страдал.

Если кто-то не понял весь юмор ситуации, то поясню. Функция memset() не работает из-за простейшей ошибки. Третий аргумент вычисляет размер указателя, а вовсе не структуры. Корректный вызов должен выглядеть так: "memset(this, 0, sizeof(*this));". 

Кстати, рядом у этого программиста функция memcpy() тоже работает плохо. Уверен, что он считает разработчиков компиляторов криворукими созданиями.

Код
void Assign(const AVSValue* src, bool init) {
  if (src->IsClip() && src->clip)
    src->clip->AddRef();
  if (!init && IsClip() && clip)
    clip->Release();
  // make sure this copies the whole struct!
  //((__int32*)this)[0] = ((__int32*)src)[0];
  //((__int32*)this)[1] = ((__int32*)src)[1];
  memcpy(this,src,sizeof(this));
}


Из комментариев видно, что он пытался копировать память альтернативными методами. Впрочем, потом оставил всё-таки функцию 'memcpy()'. Возможно она у него работала в 64-битной программе. Там размер указателя равен 8 байт. А именно 8 байт, он и хочет скопировать.

Ошибка опять в третьем аргументе. Должно быть написано "sizeof(*this)".

Вот так и рождаются легенды о глючных компиляторах и отважных программистах, которые с ними сражаются.

Вывод

Если что-то работает не так, ищите ошибку в своём коде.

P.S.

Как я наткнулся на эти ошибки? Очень просто - я использовал анализатора кода PVS-Studio.

--------------------
Карпов Андрей, DevRel в PVS-Studio.
PM MAIL WWW   Вверх
boostcoder
Дата 10.9.2012, 14:43 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

Репутация: 20
Всего: 110



жуть какая smile 
как его код вообще приняли?!
PM WWW   Вверх
xvr
Дата 11.9.2012, 11:17 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Самая главная ошибка любого компилятора в том, что он компилирует то, что программист написал, а не то, о чем он думал  smile 

PM MAIL   Вверх
borisbn
Дата 11.9.2012, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 21
Всего: 135



Кстати, по поводу memcpy. Недавно нарвался у себя в коде на такую ошибку: в шаблонном классе есть такой код
Код
memcpy( & m_outData[ count ], &v[ 0 ], v.size() );

где m_outData - указатель на T, v - vector< T >.
пока T у меня был unsigned char всё работало...
На самом деле нужно было v.size() * sizeof( T ), хотя ещё лучше каким нибудь std::copy, но суть не в этом.
PVS-Studio ничего в этой строке не увидел. Я ни в коем случае не утверждаю что должен был, но м.б. стОит подумать, что можно сделать в такой ситуации ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
Dem_max
Дата 11.9.2012, 17:34 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Да в принципе такой код memset(this, 0, sizeof(*this)); тоже страшен сам по себе.


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
bsa
Дата 11.9.2012, 22:17 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Dem_max, согласен. При использовании memset в тело класса следует добавить комментарий большими буквами: //WARNING: Use only POD types here because memset used in constructor.
PM   Вверх
borisbn
Дата 11.9.2012, 23:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 21
Всего: 135



Вопрос к Андрею Карпову: это - http://forum.vingrad.ru/forum/topic-356293.html - UB, ошибка компилятора или всё штатно по стандарту ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 12.9.2012, 08:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

Репутация: 20
Всего: 110



Цитата(borisbn @  11.9.2012,  14:52 Найти цитируемый пост)
PVS-Studio ничего в этой строке не увидел. Я ни в коем случае не утверждаю что должен был, но м.б. стОит подумать, что можно сделать в такой ситуации ?

присоединяюсь к вопросу.

PM WWW   Вверх
Thunderbolt
Дата 12.9.2012, 11:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


DevRel
*


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

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



Цитата(borisbn @ 11.9.2012,  23:38)
Вопрос к Андрею Карпову: это - http://forum.vingrad.ru/forum/topic-356293.html - UB, ошибка компилятора или всё штатно по стандарту ?

Тут всё штатно. Просто у разработчиков странные и неправильные представления о числах с плавающё точкой. Нодо многое о них знать, чтобы правильно с ними работать. Вот я бы не сказал, что умею. Там масса тонкостей.

Ещё немного на эту тему:

http://www.viva64.com/ru/b/0074/

http://www.drdobbs.com/cpp/are-you-sure-th...works/240006889

Добавлено через 3 минуты и 47 секунд
Цитата(borisbn @ 11.9.2012,  14:52)
Я ни в коем случае не утверждаю что должен был, но м.б. стОит подумать, что можно сделать в такой ситуации ?

Да, про такой паттерн PVS-Studio не знает. Записал пример в список улучшений. Спасибо.
--------------------
Карпов Андрей, DevRel в PVS-Studio.
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

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

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

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

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


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

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


 




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


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

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