Мои вопросы разделены на три части
Вопрос 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, тестируют main.cpp, используется для формирования исполняемого файла.
По-видимому очень простой код, имеет нечетное поведение в SUSE 64 бита ОС, gcc версия 4.1.2. Ожидаемый вывод является "Числом, отрицательно", вместо этого только в SUSE 64 бита ОС, вывод был бы "Числом, положительно".
После некоторого объема анализа и выполнения 'disass' кода, я нахожу, что компилятор оптимизирует в ниже формата -
if ( v < 0 )
, где v является положительной константой, Таким образом, во время самой компиляции, еще адрес функции суда части добавляется к регистру. Никакие cmp/jmp инструкции не могут быть найдены.Я вижу, что поведение находится только в gcc 4.1.2 SUSE 10. При попытке в AIX 5.1/5.3 и HP IA64 результат как ожидалось.
Допустима вышеупомянутая оптимизация?
Или, действительно ли использование является водосливным механизмом для интервала не допустимый вариант использования?
Вопрос 2
Теперь, когда я изменяю условный оператор от if (i + v < i)
кому: if ( (i + v) < i )
даже затем поведение - то же, это по крайней мере я лично не согласился бы, так как дополнительные фигурные скобки обеспечиваются, я ожидаю, что компилятор для создания временной встроенной переменной типа и их выдерживает сравнение, таким образом аннулирует оптимизацию.
Вопрос 3
Предположим, что у меня есть огромная кодовая база, я перемещают мою версию компилятора, такая ошибка/оптимизация может вызвать опустошение в моем поведении системы. Конечно, с бизнес-точки зрения, это очень неэффективно для тестирования всех строк кода снова только из-за компилятора upgradation.
Я думаю для всей практической цели, эти виды ошибки очень трудно поймать (во время upgradation) и неизменно будут пропущены к месту производства.
Кто-либо может предложить какой-либо возможный способ удостовериться, чтобы гарантировать, что подобные ошибка/оптимизация не оказывает влияния на мою существующую систему/кодовую базу?
PS:
Обновление (1)
Чего я хотел бы достигнуть? переменная я был бы счетчиком (вид syncID). Если бы я делаю офлайновую операцию (50 операций) затем во время запуска, я хотел бы сбросить свой счетчик, Для этого я проверяю граничное значение (для сброса его) вместо того, чтобы добавить его вслепую.
Я не уверен, полагаюсь ли я на аппаратную реализацию. Я знаю, что 0X7FFFFFFF является макс. положительным значением. Все, что я делаю, путем увеличивания стоимость этого, я ожидаю, что возвращаемое значение будет отрицательно. Я не думаю, что эта логика имеет какое-либо отношение к аппаратной реализации.
Так или иначе, все спасибо за Ваш вход.
Обновление (2)
Большинство inpit указывает, что я полагаюсь на более низкое поведение уровня на проверке переполнения. У меня есть вопросы относительно того же,
Я не смог бы сделать это, если я не проверяю на отрицательность числа. Таким образом, мое требование состоит в том, что интервал должен возвратить отрицательное число, когда значение добавляется к +MAX_INT.
Сообщите мне свои исходные данные.
Это известная проблема, и я не думаю, что она считается ошибкой в компиляторе. Когда я компилирую с gcc 4.5 с -Wall -O2
, он предупреждает
предупреждение: при условии, что подписанное переполнение не происходит, если предполагается, что (X + c)
Хотя ваш код вызывает переполнение .
Вы можете передать флаг -fno-strict-overflow
, чтобы отключить данную оптимизацию.
Q1: Возможно, число действительно положительное в 64-битной реализации? Кто знает? Перед отладкой кода я бы просто printf ("% d", i + v);
Q2: круглые скобки нужны только для того, чтобы сообщить компилятору, как анализировать выражение. Обычно это делается в виде дерева, поэтому оптимизатор вообще не видит скобок. И выражение можно изменить бесплатно.
Q3: Вот почему, как программист c / c ++, вы не должны писать код, предполагающий определенные свойства базового оборудования, такие как, например, что int - это 32-битная величина в форме дополнения до двух.
Что выводит строка:
cout<<(i + v)<<endl;
в примере SUSE? Вы уверены, что у вас нет 64-битных целых чисел?
Ваш код приводит к неопределенному поведению. Языки C и C++ не имеют "механизма переполнения" для целочисленной арифметики со знаком. Ваши вычисления переполняют знаковые целые числа - поведение сразу же становится неопределенным. Рассмотрение этого с позиции "ошибка в компиляторе или нет" ничем не отличается от попытки анализа примеров i = i++ ++i
.
Компилятор GCC имеет оптимизацию, основанную на этой части спецификации языков Си/Си++. Она называется "строгая семантика переполнения" или что-то вроде этого. Она основана на том, что добавление положительного значения к знаковому целому числу в C++ всегда дает большее значение или приводит к неопределенному поведению. Это сразу же означает, что компилятор совершенно свободно может считать, что сумма всегда больше. Общая природа этой оптимизации очень похожа на оптимизацию "strict aliasing", которая также присутствует в GCC. Обе они привели к некоторым жалобам со стороны более "хакерски настроенной" части сообщества пользователей GCC, многие из которых даже не подозревали, что трюки, на которые они полагались в своих программах на C/C++, были просто незаконными хаками.