У меня очень странная ошибка в моей программе. Я не смог выделить ошибку в воспроизводимом коде, но в определенном месте в моем коде есть:
double distance, criticalDistance;
...
if (distance > criticalDistance)
{
std::cout << "first branch" << std::endl;
}
if (distance == criticalDistance)
{
std::cout << "second branch" << std::endl;
}
В отладочной сборке все нормально. Выполняется только одна ветвь.
Но в релизной сборке все чертовски рвется и иногда обе ветви исполняются.
Это очень странно, так как, если я добавлю еще условно:
if (distance > criticalDistance)
{
std::cout << "first branch" << std::endl;
}
else if (distance == criticalDistance)
{
std::cout << "second branch" << std::endl;
}
Такого не бывает.
Пожалуйста, что может быть причиной этого? я использую gcc 4.8.1 на Ubuntu 13.10 на 32 бит компьютер.
EDIT1:
Я использую флаги прекомпилятора
EDIT2:
Я не думаю, что это вызвано утечкой памяти. Я проанализировал обе версии: Valgrind Анализатор памяти с отслеживанием унифицированной памяти и обнаружением кода самодиагностики, и я не обнаружил ошибок.
EDIT3:
Изменение декларации на
volatile double distance, criticalDistance;
делает проблему уйти. Это подтверждает ответ WoSstar? Это ошибка компилятора?
EDIT4:
используя опцию gcc -ffloat-магазин также исправляет проблему. Если я правильно понимаю, это вызвано gcc.
if (distance > criticalDistance)
// true
if (distance == criticalDistance)
// also true
Я видел это поведение раньше в моем собственном коде. Это связано с несоответствием между стандартным 64-битным значением, хранящимся в памяти, и 80-битными внутренними значениями, которые процессоры Intel используют для вычисления с плавающей запятой.
По сути, при усечении до 64 битов ваши значения равны, но при тестировании при 80-битных значениях одно немного больше другого. В DEBUG
В режиме значения всегда сохраняются в памяти, а затем перезагружаются, поэтому они всегда усекаются. В оптимизированном режиме компилятор повторно использует значение в регистре с плавающей запятой, и оно не усекается.
Пожалуйста, что может быть причиной этого?
Неопределенное поведение, ака. ошибки в вашем коде.
Не существует значения IEEE с плавающей запятой, которое демонстрирует такое поведение. Так что происходит, что вы делаете что-то неправильно, что нарушает предположение, сделанное вашим компилятором.
При оптимизации вашего кода компилятор предполагает, что ваш код может быть описан стандартом C ++. Если вы делаете что-то, что не определено стандартом C ++, эти предположения нарушаются, что приводит к «странному» выполнению. Это может быть что-то «простое», например, неинициализированная переменная или переполнение буфера, в результате чего части стека или кучи перезаписываются мусорными данными, или это может быть что-то более тонкое, когда вы полагаетесь на определенный порядок между двумя операциями, который не гарантируется стандартом.
Возможно, именно поэтому вы не смогли воспроизвести проблему в небольшом тестовом примере (меньший тестовый код не содержит ошибочный код) или и почему вы видите ошибку только в оптимизированных сборках.
Конечно, также возможно, что вы наткнулись на ошибку компилятора, но ошибка в вашем коде более вероятна. 🙂
И, самое главное, это означает, что у нас нет шансов отладить проблему из фрагмента кода, который вы показали. Мы можем сказать «код не должен вести себя так», но это все.
Вы не инициализируете свои двойники, вы уверены, что они всегда получают значение?
Я обнаружил, что неинициализированные переменные в отладке всегда равны 0, но в выпуске они могут быть чем угодно.