Чудеса инкремента...
От: Павел Кузнецов  
Дата: 02.09.02 16:22
Оценка: 117 (10)
#Имя: FAQ.cpp.undefined
J>Мне вот интересно, а что должно получится в результате следующего выражения в переменной j:

int i=1;
int j;
j=(++i)*2+ --i;


Это известный пример так называемого неопределенного поведения, что является одной из худших ошибок программирования, т.к. в отличие от других она может "прикидываться" вполне законной конструкцией. В данном случае сказываются следующие моменты:

1) в общем модификация и запись в ячейку памяти не является атомарной операцией (на некоторых системах компилятору, например, требуется загрузить значение в регистр, инкрементировать его, после чего записать его обратно);

2) стандарт не требует от компилятора генерации "постоянной" записи промежуточных значений (подобно тому как кэшируются операции с диском);

3) попытка одновременной записи в одну ячейку может закончиться очень и очень плохо: от изменяющегося от компилятора к компилятору (самый вероятный сценарий), от билда к билду (тоже бывает), или даже от запуска к запуску значения выражения до нестабильной работы системы и/или core dump в зависимости от самых различных факторов;

4) хорошей новостью является то, что в C++ определены так называемые точки следования (sequence points), в которых гарантируется, что любые операции записи таки совершились, например, точками следования сопровождаются вызовы функций, операции ||, && и т.д.;

5) в общем случае одну и ту же переменную между двумя точками следования безопасно можно модифицировать только один раз;

6) так вот, в приведенном выражении между двумя модификациями i нет точки следования, что приводит к неопределенному поведению, иначе говоря, компилятор волен творить любые фокусы, как иногда шутят, даже генерировать код для форматирования диска.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.