Чудеса инкремента...
От: Jack Украина http://tr.dn.ua/~dionis/
Дата: 02.09.02 15:47
Оценка:
Привет!
Мне вот интересно, а что должно получится в результате следующего выражения в переменной j:

int i=1;
int j;
j=(++i)*2+ --i;
Искренне Ваш, Джек.
Re: Чудеса инкремента...
От: x-fire Россия  
Дата: 02.09.02 15:53
Оценка: 14 (2)
Ничего хорошего. Всё зависит от компилятора. Это как задачка с пятью плюсами.
В справочнике у Страуструпа написано про это. И зачем так делать — запутать врага?
А как же про корректно написанный код и всё — такое?
мы идём ...
Чудеса инкремента...
От: Павел Кузнецов  
Дата: 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 нет точки следования, что приводит к неопределенному поведению, иначе говоря, компилятор волен творить любые фокусы, как иногда шутят, даже генерировать код для форматирования диска.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Чудеса инкремента...
От: Кодт Россия  
Дата: 03.09.02 11:29
Оценка:
Здравствуйте Павел Кузнецов, Вы писали:

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


ПК>5) так вот, в приведенном выражении между двумя модификациями i нет точки следования, что приводит к неопределенному поведению, иначе говоря, компилятор волен творить любые фокусы, как иногда шутят, даже генерировать код для форматирования диска.


А кстати, как может возникнуть критический код?
Разве что компилятор вставит jmp на код, который по его недо-разумению никода не должен выполняться.

Вот хотелось бы узнать...
Перекуём баги на фичи!
Re[2]: Чудеса инкремента...
От: dupamid Россия  
Дата: 04.09.02 11:48
Оценка: 18 (1)
Здравствуйте Павел Кузнецов, Вы писали:

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

ПК>2) стандарт не требует от компилятора генерации "постоянной" записи промежуточных значений (подобно тому как кэшируются операции с диском);
ПК>3) попытка одновременной записи в одну ячейку может закончиться очень и очень плохо: от изменяющегося от компилятора к компилятору (самый вероятный сценарий), от билда к билду (тоже бывает), или даже от запуска к запуску значения выражения до нестабильной работы системы и/или core dump в зависимости от самых различных факторов;
ПК>4) хорошей новостью является то, что в C++ определены так называемые точки следования (called sequence) points), в которых гарантируется, что любые операции записи таки совершились, например, точками следования сопровождаются вызовы функций, операции ||, && и т.д.;
ПК>5) в общем случае одну и ту же переменную между двумя точками следования безопасно можно модифицировать только один раз;
ПК>5) так вот, в приведенном выражении между двумя модификациями i нет точки следования, что приводит к неопределенному поведению, иначе говоря, компилятор волен творить любые фокусы, как иногда шутят, даже генерировать код для форматирования диска.

Такая интерпретация точек следования и неопределенного поведения не совсем точна, она проста для запоминания, но надо понимать, что она не полностью соответствует действительности. Начнем с простых примеров:
int i;
i = i = 1;

Здесь хотя значение переменной меняется дважды между точками следования, никакого неопределенного поведения не возникает, и результат по Стандарту должен быть один: переменная i должна иметь значение 1. Компилятор обязан сгенерировать код, который не должен приводить к фатальным последствиям даже в случае, если целевой процессор имеет два конвейера, и если они будут одновременно писать в одну и ту же ячейку памяти произойдет сбой. Так как результат этого примера не зависит от порядка вычислений.

Более сложный пример:
int i;
i = ++i;

Так же результат определен. Любая последовательность вычислений допустимых по Стандарту будет, приводит к одному и тому же результату.

Еще более ложный пример:
int i,j,k;
i = (i = j + k) + (i = j - k);

Здесь на основании статического анализа нельзя сказать будет ли неопределенное поведение при выполнении этого фрагмента кода. При j == 0, k == 0 и i == 0 результат четко определен, так как любая последовательность вычислений будет приводить к одному и тому же результату, при других значениях результат не определен и возникает неопределенное поведение.

Последний пример наглядно показывает всю сложность проблемы, если бы надо было контролировать только двукратное изменение одной переменной между точками следования, то такой анализ можно провести статически и компиляторы бы это делали и выдавали соответствующие ошибки при компиляции. Компилятор при компиляции может обнаружить только потенциальное нарушение и может выдать только предупреждение, но никак не ошибку, так как в зависимости от значений переменных поведение может быть как жестко определенным, так и неопределенным и приводить к печальным последствиям.
Re[3]: Неопределенное поведение, побочные эффекты и оптимиза
От: Кодт Россия  
Дата: 04.09.02 12:37
Оценка: 11 (1)
Здравствуйте dupamid, Вы писали:

D>Здравствуйте Павел Кузнецов, Вы писали:


ПК>> <skipped>


D>Такая интерпретация точек следования и неопределенного поведения не совсем точна, она проста для запоминания, но надо понимать, что она не полностью соответствует действительности. Начнем с простых примеров:


D>Еще более ложный (сложный?) пример:

D>
D>int i,j,k;
D>i = (i = j + k) + (i = j - k);
D>

D>Здесь на основании статического анализа нельзя сказать будет ли неопределенное поведение при выполнении этого фрагмента кода. При j == 0, k == 0 и i == 0 результат четко определен, так как любая последовательность вычислений будет приводить к одному и тому же результату, при других значениях результат не определен и возникает неопределенное поведение.

Поскольку компьютер (в т.ч. компилятор и порожденная программа) — это как-бы детерминированное устройство, то поведение всегда "определено".
Так что говорить о том "если бы все были = 0..." — немного не то.

imho, неопределенное поведение — это такое явление, когда на основании только исходного описания (программа на Си + конвенции) принципиально невозможно вывести результат.

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


Еще одни грабли (не называющиеся, впрочем, неопределенным поведением) — это вызов функций с побочным эффектом в бинарных операторах.
int print(int i)
{
  printf("%d\n", i);
  return i;
}

void main()
{
  int x = 3 + print(1) + 4 + print(2) + 5; // специально напихал побольше слагаемых - чтобы оптимизация была
}

Компилятору нет указаний о порядке вычисления, поэтому в разных условиях будет цирк.

Более навороченный случай:
int x;
int sideffect(int y, int z)
{
  x = y;
  return z;
}

void test(int a, int b, int c)
{
  x = a;
  int t = x * sideffect(b, c);
}
// варианты трансляции:
{
  int t1 = x; // = a
  if(t1 == 0)
    t = 0; // x = 0, t = 0
  else
    t = t1 * sideffect(b,c); // x = b, t = a*c
}
{
  int t1 = x;
  t = t1 * sideffect(b,c); // x = b; t = a*c
}
{
  int t1 = sideffect(b,c); // x = b; t1 = c
  t = x * t1; // x = b; t = b*c
}


Еще одно аналогичное явление — использование не-volatile переменных (оптимизирующий компилятор может кэшировать не-volatile переменные, и в результате побочных эффектов — например, многозадачности, — произойдет рассогласование кэша и оригинала).
Перекуём баги на фичи!
Re[4]: Неопределенное поведение, побочные эффекты и оптимиза
От: dupamid Россия  
Дата: 04.09.02 12:50
Оценка:
Здравствуйте Кодт, Вы писали:

К>Поскольку компьютер (в т.ч. компилятор и порожденная программа) — это как-бы детерминированное устройство, то поведение всегда "определено".

К>Так что говорить о том "если бы все были = 0..." — немного не то.

В Стандарте выполнение программы описывается ввиде абстрактной машины для которой нет требования детерминированности 1.9/1, так что говорить об это можно и нужно.

1.9
1. The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.5)

5) This provision is sometimes called the “asif” rule, because an implementation is free to disregard any requirement of this International Standard as long as the result is as if the requirement had been obeyed, as far as can be determined from the observable behavior of the program. For instance, an actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no side effects affecting the observable behavior of the program are produced.

3. Certain other aspects and operations of the abstract machine are described in this International Standard as unspecified (for example, order of evaluation of arguments to a function). Where possible, this International Standard defines a set of allowable behaviors. These define the nondeterministic aspects of the abstract machine. An instance of the abstract machine can thus have more than one possible execution sequence for a given program and a given input.

4. Certain other operations are described in this International Standard as undefined (for example, the effect of dereferencing the null pointer). [Note: this International Standard imposes no requirements on the behavior of programs that contain undefined behavior.]
Re[3]: Чудеса инкремента...
От: Павел Кузнецов  
Дата: 04.09.02 13:08
Оценка:
Здравствуйте dupamid, Вы писали:

ПК>> <...> в общем случае одну и ту же переменную между двумя точками следования безопасно можно модифицировать только один раз; <...> в приведенном выражении между двумя модификациями i нет точки следования, что приводит к неопределенному поведению


D>Такая интерпретация точек следования и неопределенного поведения не совсем точна, она проста для запоминания, но надо понимать, что она не полностью соответствует действительности.


Напротив, именно это и является руководством к идентификации неопределенности поведения в подобных случаях:

5 Expressions
4 Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.

D>Начнем с простых примеров:

D>
D>int i;
D>i = i = 1;
D>

D>Здесь хотя значение переменной меняется дважды между точками следования, никакого неопределенного поведения не возникает, и результат по Стандарту должен быть один: переменная i должна иметь значение 1.

Это где стандарт определяет такое поведение?

D> <...> Так как результат этого примера не зависит от порядка вычислений.


Это никак не влияет на определенность поведения. Неопределенность возникает именно из-за того, что содержимое ячейки меняется дважды между точками следования, не важно меняется ли оно на одно и то же значение или нет.

D>Более сложный пример:

D>
D>int i;
D>i = ++i;
D>

D>Так же результат определен.

Снова-таки, пример неопределенного поведения. Можешь поискать свою подстроку в видах "i = ++i", "i = i++", "x = ++x" и "x = x++" или "assignment increment undefined behavior" в comp.std.c++ или comp.lang.c++.moderated — там это регулярно обсуждается.

См. также C faq

D>Любая последовательность вычислений допустимых по Стандарту будет, приводит к одному и тому же результату.


Никакая последовательность действий не определяется стандартом. Стандарт, согласно 5/4, умывает руки и поведение всей программы является неопределенным.

D>Еще более ложный пример:

D>
D>int i,j,k;
D>i = (i = j + k) + (i = j - k);
D>

D>Здесь на основании статического анализа нельзя сказать будет ли неопределенное поведение при выполнении этого фрагмента кода.

Можешь не гадать: оно уже есть.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: Неопределенное поведение, побочные эффекты и оптимиза
От: Павел Кузнецов  
Дата: 04.09.02 13:20
Оценка:
Здравствуйте Кодт, Вы писали:

К>Еще одни грабли (не называющиеся, впрочем, неопределенным поведением) — это вызов функций с побочным эффектом в бинарных операторах.


Это называется unspecified behavior. Т.е., в данном случае, порядок побочных эффектов неопределен. Программа в целом при этом остается в границах, описываемых стандартом. При undefined behavior же, стандарт не накладывает никаких ограничений на поведение программы, т.е. это, можно сказать, больше не программа на C++.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Чудеса инкремента...
От: Аноним  
Дата: 04.09.02 13:26
Оценка:
Здравствуйте dupamid, Вы писали:

D>Такая интерпретация точек следования и неопределенного поведения не совсем точна, она проста для запоминания, но надо понимать, что она не полностью соответствует действительности.


Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored.

D>int i;
D>i = i = 1;


Undefined behavior.

D>int i;
D>i = ++i;


Undefined behavior.

D>Еще более ложный пример:


Sic!

D>int i,j,k;
D>i = (i = j + k) + (i = j - k);


Undefined behavior.

(Ну и, строго говоря, в двух последних примерах неопределенное поведение еще раньше — из-за использования неинициализированной переменной.)

Право, Вы бы уж что-нибудь более сложное придумали. Вот хоть такое:

int i = 0;
i = (i++, 0) + (i++, 0);


Или в очередной раз вспомнили бы про опечатку undefined vs. unspecified.
Re[4]: Неопределенное поведение, побочные эффекты и оптимиза
От: Аноним  
Дата: 04.09.02 13:42
Оценка:
Здравствуйте Кодт, Вы писали:

К>imho, неопределенное поведение — это такое явление, когда на основании только исходного описания (программа на Си + конвенции) принципиально невозможно вывести результат.


Примерно так.

behavior, such as might arise upon use of an erroneous program construct or erroneous data, for which this International Standard imposes no requirements.

К>Еще одни грабли (не называющиеся, впрочем, неопределенным поведением) — это вызов функций с побочным эффектом в бинарных операторах.

К>int print(int i)
К>{
К>  printf("%d\n", i);
К>  return i;
К>}

К>void main()
К>{
К>  int x = 3 + print(1) + 4 + print(2) + 5; // специально напихал побольше слагаемых - чтобы оптимизация была
К>}

К>Компилятору нет указаний о порядке вычисления, поэтому в разных условиях будет цирк.

Будет только разная последовательность вывода чисел 1 и 2. Это — unspecified behavior, а не undefined.

К>Более навороченный случай:

К>int x;
К>int sideffect(int y, int z)
К>{
К>  x = y;
К>  return z;
К>}

К>void test(int a, int b, int c)
К>{
К>  x = a;
К>  int t = x * sideffect(b, c);
К>}
К>// варианты трансляции:
К>{
К>  int t1 = x; // = a
К>  if(t1 == 0)
К>    t = 0; // x = 0, t = 0
К>  else
К>    t = t1 * sideffect(b,c); // x = b, t = a*c
К>}
К>{
К>  int t1 = x;
К>  t = t1 * sideffect(b,c); // x = b; t = a*c
К>}
К>{
К>  int t1 = sideffect(b,c); // x = b; t1 = c
К>  t = x * t1; // x = b; t = b*c
К>}


Из этих вариантов трансляции возможен только второй.

К>Еще одно аналогичное явление — использование не-volatile переменных (оптимизирующий компилятор может кэшировать не-volatile переменные, и в результате побочных эффектов — например, многозадачности, — произойдет рассогласование кэша и оригинала).


Ну да, так для того и voiatile.
Re[4]: Чудеса инкремента...
От: dupamid Россия  
Дата: 04.09.02 13:50
Оценка:
Здравствуйте Павел Кузнецов, Вы писали:

ПК>Напротив, именно это и является руководством к идентификации неопределенности поведения в подобных случаях:


ПК>5 Expressions

ПК>4 Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.

Крайне интересная ссылочка! Приведу ее полностью:
5
4. Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified.53) Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined. [Example:
i = v[i++]; // the behavior is unspecified
i = 7, i++, i++; // i becomes 9
i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented
—end example]

Как тут уже заметили undefined или unspecified! Это две большие разницы. Если все таки unspecified, то результаты выполнения этих примеров жестко определены.

D>>Начнем с простых примеров:

D>>
D>>int i;
D>>i = i = 1;
D>>

D>>Здесь хотя значение переменной меняется дважды между точками следования, никакого неопределенного поведения не возникает, и результат по Стандарту должен быть один: переменная i должна иметь значение 1.

ПК>Это где стандарт определяет такое поведение?


А где он это запрещает.

D>> <...> Так как результат этого примера не зависит от порядка вычислений.


ПК>Это никак не влияет на определенность поведения. Неопределенность возникает именно из-за того, что содержимое ячейки меняется дважды между точками следования, не важно меняется ли оно на одно и то же значение или нет.


D>>Более сложный пример:

D>>
D>>int i;
D>>i = ++i;
D>>

D>>Так же результат определен.

ПК>Снова-таки, пример неопределенного поведения. Можешь поискать свою подстроку в видах "i = ++i", "i = i++", "x = ++x" и "x = x++" или "assignment increment undefined behavior" в comp.std.c++ или comp.lang.c++.moderated — там это регулярно обсуждается.


ПК>См. также C faq


Это ссылка про С 95 года да и про пост-инкримент, а не про прединкримент.

D>>Любая последовательность вычислений допустимых по Стандарту будет, приводит к одному и тому же результату.


ПК>Никакая последовательность действий не определяется стандартом. Стандарт, согласно 5/4, умывает руки и поведение всей программы является неопределенным.


D>>Еще более ложный пример:

D>>
D>>int i,j,k;
D>>i = (i = j + k) + (i = j - k);
D>>

D>>Здесь на основании статического анализа нельзя сказать будет ли неопределенное поведение при выполнении этого фрагмента кода.

ПК>Можешь не гадать: оно уже есть.
Re[5]: Неопределенное поведение, побочные эффекты и оптимиза
От: Кодт Россия  
Дата: 04.09.02 14:04
Оценка:
Здравствуйте Аноним, Вы писали:

К>>Более навороченный случай:

К>>int x;
К>>int sideffect(int y, int z)
К>>{
К>>  x = y;
К>>  return z;
К>>}

К>>void test(int a, int b, int c)
К>>{
К>>  x = a;
К>>  int t = x * sideffect(b, c);
К>>}
К>>// варианты трансляции:
К>>{
К>>  int t1 = x; // = a
К>>  if(t1 == 0)
К>>    t = 0; // x = 0, t = 0
К>>  else
К>>    t = t1 * sideffect(b,c); // x = b, t = a*c
К>>}
К>>{
К>>  int t1 = x;
К>>  t = t1 * sideffect(b,c); // x = b; t = a*c
К>>}
К>>{
К>>  int t1 = sideffect(b,c); // x = b; t1 = c
К>>  t = x * t1; // x = b; t = b*c
К>>}


А>Из этих вариантов трансляции возможен только второй.

???

"Дорожные знаки написаны кровью".
Этот пример родился как память о нескольких днях муторной отладки, когда дебаг-версия жужжала, а релиз — нет. Только там выражение позаковыристей было (на десяток строчек), а то, что сделала оптимизация — ууууу!
Перекуём баги на фичи!
Re[5]: Чудеса инкремента...
От: Павел Кузнецов  
Дата: 04.09.02 14:14
Оценка:
Здравствуйте dupamid, Вы писали:

D>Крайне интересная ссылочка! Приведу ее полностью:

D>5
D>4. Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified.53)

^ При обсуждении данного вопроса это можно выкинуть.

D>Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression.


^ В принципе, этого было бы достаточно, но для полноты картины следующее тоже не помешает.

D>Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.


Примеры не являются нормативной частью стандарта, кроме того, уже известно (хотя и не закреплено голосованием комитета), что в данном содержатся две опечатки, касающиеся именно слов unspecified, так что остается именно то, что я и процитировал изначально.

D>[Example:

D>i = v[i++]; // the behavior is unspecified
D>i = 7, i++, i++; // i becomes 9
D>i = ++i + 1; // the behavior is unspecified
D>i = i + 1; // the value of i is incremented
D>—end example]

D>Как тут уже заметили undefined или unspecified! Это две большие разницы. Если все таки unspecified, то результаты выполнения этих примеров жестко определены.


Все-таки undefined.

D>А где он это запрещает.


В процитированном кусочке (выделено мною): "Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. ... The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined" В стандарте слово shall означает обязательность выполнения требования. Программа, не соответствующая данному требованию, выходит за рамки стандарта, т.е. ее поведение is undefined, что для ясности в сложных случаях еще и подкреплено последним предложением.

D>>>Более сложный пример:

D>>>
D>>>int i;
D>>>i = ++i;
D>>>

D>>>Так же результат определен.

<...>

ПК>>См. также C faq


D>Это ссылка про С 95 года да и про пост-инкримент, а не про прединкримент.


Это не важно, эти правила были унаследованы из C в неизменном виде. Более того, там где явно не сказано обратное, C++ соответствует стандарту C89/90, так как включает его по ссылке. Кроме того, мог бы все-таки поискать, как тебе предлагалось в архивах comp.std.c++ — это официальная группа для разрешения подобных вопросов.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[5]: Чудеса инкремента...
От: Аноним  
Дата: 04.09.02 14:36
Оценка:
Здравствуйте dupamid, Вы писали:

D>Крайне интересная ссылочка! Приведу ее полностью:

D>5
D>4. Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified.53) Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined. [Example:
D>i = v[i++]; // the behavior is unspecified
D>i = 7, i++, i++; // i becomes 9
D>i = ++i + 1; // the behavior is unspecified
D>i = i + 1; // the value of i is incremented
D>—end example]

D>Как тут уже заметили undefined или unspecified! Это две большие разницы. Если все таки unspecified, то результаты выполнения этих примеров жестко определены.


DR уже подал Andrew Koenig: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_active.html#351
Re[6]: Чудеса инкремента...
От: Павел Кузнецов  
Дата: 04.09.02 14:46
Оценка:
Здравствуйте Аноним, Вы писали:

D>>Как тут уже заметили undefined или unspecified! Это две большие разницы. Если все таки unspecified, то результаты выполнения этих примеров жестко определены.


А>DR уже подал Andrew Koenig: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_active.html#351


Ситуация становится интереснее в присутствии http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_active.html#222
Так что, поживем — увидим :-)
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: Неопределенное поведение, побочные эффекты и оптимиза
От: Аноним  
Дата: 04.09.02 14:54
Оценка:
Здравствуйте Кодт, Вы писали:

К>>>int x;
К>>>int sideffect(int y, int z)
К>>>{
К>>>  x = y;
К>>>  return z;
К>>>}

К>>>void test(int a, int b, int c)
К>>>{
К>>>  x = a;
К>>>  int t = x * sideffect(b, c);
К>>>}
К>>>// варианты трансляции:
К>>>{
К>>>  int t1 = x; // = a
К>>>  if(t1 == 0)
К>>>    t = 0; // x = 0, t = 0
К>>>  else
К>>>    t = t1 * sideffect(b,c); // x = b, t = a*c
К>>>}


А>>Из этих вариантов трансляции возможен только второй.

К>???

К>"Дорожные знаки написаны кровью".

К>Этот пример родился как память о нескольких днях муторной отладки, когда дебаг-версия жужжала, а релиз — нет. Только там выражение позаковыристей было (на десяток строчек), а то, что сделала оптимизация — ууууу!

Брррр... То есть Вы хотите сказать, что мог быть выброшен вызов функции с побочными эффектами, если один из операндов умножения — ноль?.. М-да, что ж это за компилятор такой?
Re[7]: Чудеса инкремента...
От: Аноним  
Дата: 04.09.02 15:00
Оценка:
Здравствуйте Павел Кузнецов, Вы писали:

А>>DR уже подал Andrew Koenig: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_active.html#351


ПК>Ситуация становится интереснее в присутствии http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_active.html#222


Нууу, там все вообще запущено...

ПК>Так что, поживем — увидим :-)


Угу. Те, кто доживут. :)
Re[8]: Чудеса инкремента...
От: Павел Кузнецов  
Дата: 04.09.02 15:06
Оценка:
Здравствуйте Аноним, Вы писали:

ПК>>Ситуация становится интереснее в присутствии http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_active.html#222


А>Нууу, там все вообще запущено...


ПК>>Так что, поживем — увидим :-)


А>Угу. Те, кто доживут. :)


До TC уже недолго осталось: Andrew Koenig где-то говорил, что уже подали в ISO, стало быть где-то в районе нескольких месяцев – года до публикации. В любом случае, следующая версия стандарта ожидается где-то к 2008 или около того — не так уж и долго по вселенским меркам :-)
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[7]: Неопределенное поведение, побочные эффекты и оптимиза
От: Кодт Россия  
Дата: 04.09.02 15:33
Оценка:
Здравствуйте Аноним, Вы писали:

А>Здравствуйте Кодт, Вы писали:


А>Брррр... То есть Вы хотите сказать, что мог быть выброшен вызов функции с побочными эффектами, если один из операндов умножения — ноль?.. М-да, что ж это за компилятор такой?


VC5 (а может еще и 4 — уже не помню).
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.