Мои вопросы делятся на три части
Вопрос 1
Рассмотрим приведенный ниже код,
#include <iostream>
using namespace std;
int main( int argc, char *argv[])
{
const int v = 50;
int i = 0X7FFFFFFF;
cout<<(i + v)<<endl;
if ( i + v < i )
{
cout<<"Number is negative"<<endl;
}
else
{
cout<<"Number is positive"<<endl;
}
return 0;
}
Никаких конкретных опций оптимизации компилятора или флага O не используется. Это базовая команда компиляции g ++ -o test main.cpp используется для формирования исполняемого файла.
Казалось бы, очень простой код имеет странное поведение в 64-битной ОС SUSE, версия gcc 4.1.2. Ожидаемый результат - «Число отрицательно», вместо этого только в 64-битной ОС SUSE вывод будет «Число положительно».
После некоторого анализа и выполнения «разногласий» кода, я обнаружил, что компилятор оптимизирует в следующем формате -
- Поскольку i одинаково с обеих сторон сравнения, его нельзя изменить в одном выражении, уберите «i» из уравнения.
- Теперь сравнение приводит к
if ( v < 0 )
, где v - постоянная положительная величина, поэтому во время самой компиляции адрес функции функции остальной части cout добавляется в регистр. Инструкции cmp / jmp не найдены.
Я вижу, что это поведение только в gcc 4.1.2 SUSE 10. При попытке в AIX 5.1 / 5.3 и HP IA64 результат будет таким, как ожидалось.
Является ли приведенная выше оптимизация действительной?
Или использование механизма переполнения для int не является допустимым вариантом использования?
Вопрос 2
Теперь, когда я изменяю условный оператор с if (i + v < i)
на if ( (i + v) < i )
, даже тогда поведение такое же, по крайней мере, лично я с этим не согласен, так как предоставляются дополнительные скобки, я ожидаю, что компилятор создаст временную переменную встроенного типа и их сравнивают, что сводит на нет оптимизацию.
Вопрос 3
Предположим, у меня огромная база кода, и я переношу версию своего компилятора, такая ошибка / оптимизация может вызвать хаос в поведении моей системы. Конечно, с точки зрения бизнеса, очень неэффективно снова тестировать все строки кода только из-за обновления компилятора.
Я думаю, что с практической точки зрения эти виды ошибок очень трудно уловить (во время обновления) и неизменно попадут на производственную площадку.
Может ли кто-нибудь предложить какой-либо возможный способ гарантировать, что такого рода ошибка / оптимизация не окажет никакого влияния на мою существующую систему / кодовую базу?
PS:
- Когда const для v удаляется из кода, оптимизация не выполняется компилятором.
- Полагаю, совершенно нормально использовать механизм переполнения, чтобы определить, находится ли переменная от значения MAX - 50 (в моем случае).
Обновление (1)
Чего бы я хотел достичь? Переменная я был бы счетчиком (вид syncID). Если я выполняю автономную работу (50 операций), то во время запуска я хотел бы сбросить счетчик. Для этого я проверяю граничное значение (для его сброса), а не добавляю его вслепую.
Я не уверен, полагаюсь ли я на аппаратную реализацию. Я знаю, что 0X7FFFFFFF - максимальное положительное значение. Все, что я делаю, добавив значение к этому, я ожидаю, что возвращаемое значение будет отрицательным. Я не думаю, что эта логика имеет какое-либо отношение к аппаратной реализации.
В любом случае, все спасибо за ваш вклад.
Обновление (2)
В большинстве статей указано, что я полагаюсь на поведение нижнего уровня при проверке переполнения. У меня есть один вопрос относительно того же,
- Если это так, для неподписанного типа int, как проверить и сбросить значение во время переполнения или переполнения? например, если v = 10, i = 0X7FFFFFFE, я хочу сбросить i = 9. Точно так же для недостаточного заполнения?
Я бы не смог этого сделать, если не проверю отрицательность числа. Поэтому я утверждаю, что int должен возвращать отрицательное число, когда значение добавляется в + MAX_INT.
Пожалуйста, дайте мне знать ваши входные данные.