sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 06:15
Оценка:
Из стандарта, я понял, что вызов функции является sequence point. Если это так, объясните мне, как работает следующий фрагмент кода:

#include <iostream>

int f(int i) { return i;}

void main()
{
    int i = 0;
    std::cout << f(i) << " " << f(i++) << " " << f(++i) << " " << f(i++) << std::endl;
}


Или здесь UB? Почему?
Re: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 07:07
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Из стандарта, я понял, что вызов функции является sequence point.


Двумя.

А>Если это так, объясните мне, как работает следующий фрагмент кода:


Следующий фрагмент кода не работает.

А>#include <iostream>

А>int f(int i) { return i;}

А>void main()
А>{
А>    int i = 0;
А>    std::cout << f(i) << " " << f(i++) << " " << f(++i) << " " << f(i++) << std::endl;
А>}

А>Или здесь UB?

Да.

А>Почему?


Потому, что переменная i модифицируется более одного раза между двумя соседними точками следования.
Re[2]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 07:13
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>>Из стандарта, я понял, что вызов функции является sequence point.


А>Двумя.


то есть перед началом вызова и после вызова?

А>>Если это так, объясните мне, как работает следующий фрагмент кода:


А>Следующий фрагмент кода не работает.


он работает даже если тут UB, просто на всех компиляторах по-разному. И ИМХО нет тут никакого UB.
operator<< принимает один аргумент код эквивалентен серии вложенных вызовов operator<<
откуда здесь возмётся UB?

А>
А>>#include <iostream>

А>>int f(int i) { return i;}

А>>void main()
А>>{
А>>    int i = 0;
А>>    std::cout << f(i) << " " << f(i++) << " " << f(++i) << " " << f(i++) << std::endl;
А>>}
А>

А>>Или здесь UB?

А>Да.


А>>Почему?


А>Потому, что переменная i модифицируется более одного раза между двумя соседними точками следования.
Re: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 07:18
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Из стандарта, я понял, что вызов функции является sequence point. Если это так, объясните мне, как работает следующий фрагмент кода:


А>
А>#include <iostream>

А>int f(int i) { return i;}

А>void main()
А>{
А>    int i = 0;
А>    std::cout << f(i) << " " << f(i++) << " " << f(++i) << " " << f(i++) << std::endl;
А>}

А>


А>Или здесь UB? Почему?


В начале более простой чем у тебя пример "(a++, b++) + (c++, d++)". Здесь Стандарт гарантирует следующее a++ произойдет раньеше чем b++, и c++ произойдет раньше чем d++, но он не говорит, что левый операнд будет вычислен до правого или на оборот. Более того реализация может смешивать вычисления левого и правого операнда. Точки следования в операторе запятая нет, но есть гарантированный порядок вычисления.

Точки следования дают только относительную детерминированность. Так что в твоем примере, гарантируется, что увеличение i произойдет до вызова функции и будет сохранено в память, но в каком порядке будут вызваны функции или правильно ли произойдет увеличении не гарантируется. Так например, реализация может в начале сделать все увеличения, потом позвать все функции, а потом все напечатать. Так что вызовами функций, ты не введешь определенность порядка вычислений операндов. Кстати сказать вызов перегружженорго опратора << — это тоже точка следования, так что можно было и не вызывать функции.
Re: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 07:20
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Из стандарта, я понял, что вызов функции является sequence point. Если это так, объясните мне, как работает следующий фрагмент кода:


А>
А>#include <iostream>

А>int f(int i) { return i;}

А>void main()
А>{
А>    int i = 0;
А>    std::cout << f(i) << " " << f(i++) << " " << f(++i) << " " << f(i++) << std::endl;
А>}

А>


А>Или здесь UB? Почему?


В таком случае стандарт не гарантирует именно ту последовательность вызовов функции f(), в которой ты написал. Порядок вызовов произволен.
Re[3]: sequence point (по мотивам инкремента)
От: Bell Россия  
Дата: 04.06.04 07:25
Оценка:
Здравствуйте, Аноним, Вы писали:

А>он работает даже если тут UB, просто на всех компиляторах по-разному. И ИМХО нет тут никакого UB.

А>operator<< принимает один аргумент код эквивалентен серии вложенных вызовов operator<<
А>откуда здесь возмётся UB?

Здесь действительно нет UB. Пробрема просто в том, что порядок вычисления аргументов функции не определен.
Любите книгу — источник знаний (с) М.Горький
Re[3]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 07:25
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>>>Из стандарта, я понял, что вызов функции является sequence point.

А>>Двумя.
А>то есть перед началом вызова и после вызова?

После вычисления аргументов и после копирования возвращаемого значения.

А>>>Если это так, объясните мне, как работает следующий фрагмент кода:

А>>Следующий фрагмент кода не работает.
А>он работает даже если тут UB, просто на всех компиляторах по-разному.

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

А>И ИМХО нет тут никакого UB.

А>operator<< принимает один аргумент код эквивалентен серии вложенных вызовов operator<<
А>откуда здесь возмётся UB?

Уже было сказано, откуда:

А>>Потому, что переменная i модифицируется более одного раза между двумя соседними точками следования.


Давайте по порядку.

    f(i++) + f(i++);

Понятно, почему здесь UB?
Re[4]: sequence point (по мотивам инкремента)
От: Bell Россия  
Дата: 04.06.04 07:28
Оценка:
Здравствуйте, Аноним, Вы писали:


А>Давайте по порядку.


А>
А>    f(i++) + f(i++);
А>

А>Понятно, почему здесь UB?

Здесь нет UB. Можно привести аргументацию?
Любите книгу — источник знаний (с) М.Горький
Re[2]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 07:28
Оценка:
Здравствуйте, dupamid, Вы писали:

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


Вот это новость!..
Re[4]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 07:30
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здесь действительно нет UB.


Т.е. здесь нет нарушения требования из 5/4?
Re[5]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 07:33
Оценка: +1
Здравствуйте, Bell, Вы писали:

А>>    f(i++) + f(i++);

А>>Понятно, почему здесь UB?

B>Здесь нет UB. Можно привести аргументацию?


Можно, конечно. Здесь нет точек следования, разделяющих две модификации переменной i.
Можете ли Вы такие точки следования указать?
Re[5]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 07:37
Оценка:
Здравствуйте, Bell, Вы писали:

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



А>>Давайте по порядку.


А>>
А>>    f(i++) + f(i++);
А>>

А>>Понятно, почему здесь UB?

B>Здесь нет UB. Можно привести аргументацию?

Запишем так:
operator+(f(i++),f(i++))

Здесь есть UB только если функция f производит какие-то побочные эффекты
Смысл в том, что компилятор не гарантирует в каком порядке он вычисляет аргументы функции
operator+. operator+ — бинарный оператор, у которого аргументы одного типа. то же самое нельзя сказать
про оператор << в данном контексте. поэтому сравнение некорректно.
Re[4]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 07:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Давайте по порядку.

А>
А>    f(i++) + f(i++);
А>

А>Понятно, почему здесь UB?

Здесь нет undefined behavior, но результат неопределен — это разные вещи. Более того, несмотря на то что Павел Кузнецов утверждает, что модификация одной переменной между точками следования — есть undefined behavior, пока это не отднозначно. Но то что это как минимум unspecified behavior — это точно.
Re[6]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 07:39
Оценка:
А>Здесь есть UB только если функция f производит какие-то побочные эффекты
пардон эту строчку считать вычеркнутой здесь есть UB см. пост выше почему и почему это UB
нельзя так просто перенести на случай operator<<
Re[3]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 07:46
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>Вот это новость!..


По С99 есть, вот цитата из С99:
6.5.17 Comma operator
Syntax
1 expression:
assignment-expression
expression , assignment-expression
Semantics
2 The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation. Then the right operand is evaluated; the result has its type and value.94) If an attempt is made to modify the result of a comma operator or to access it after the next sequence point, the behavior is undefined.
3 EXAMPLE As indicated by the syntax, the comma operator (as described in this subclause) cannot appear in contexts where a comma is used to separate items in a list (such as arguments to functions or lists of initializers). On the other hand, it can be used within a parenthesized expression or within the second expression of a conditional operator in such contexts. In the function call f(a, (t=3, t+2), c) the function has three arguments, the second of which has the value 5.
Forward references: initialization (6.7.8).


По С++'04 нет:
5.18 Comma operator
1 The comma operator groups left-to-right.
expression:
assignment-expression
expression , assignment-expression
A pair of expressions separated by a comma is evaluated left-to-right and the value of the left expression is discarded. The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are not applied to the left expression. All side effects (1.9) of the left expression, except for the destruction of temporaries (12.2), are performed before the evaluation of the right expression. The type and value of the result are the type and value of the right operand; the result is an lvalue if the right operand is an lvalue, and is a bit-field if the right operand is an lvalue and a bit-field.
2 In contexts where comma is given a special meaning, [Example: in lists of arguments to functions (5.2.2) and lists of initializers (8.5) ] the comma operator as described in clause 5 can appear only in parentheses. [Example:
f(a, (t=3, t+2), c);
has three arguments, the second of which has the value 5. ]
Re[3]: sequence point (по мотивам инкремента)
От: jazzer Россия Skype: enerjazzer
Дата: 04.06.04 07:50
Оценка:
Здравствуйте, Аноним, Вы писали:

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


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


А>Вот это новость!..


тем не менее, это так.
точка следования — это когда все побочные эффекты предыдущего выражения уже сработали, а следующего — еще не начались.
Для оператора запятая гарантируется только первое.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 07:53
Оценка:
Здравствуйте, dupamid, Вы писали:

А>>Давайте по порядку.

А>>
А>>    f(i++) + f(i++);
А>>

А>>Понятно, почему здесь UB?

D>Здесь нет undefined behavior, но результат неопределен — это разные вещи.


Нет, здесь не unspecified, а именно undefined behavior.

D>Более того, несмотря на то что Павел Кузницов утверждает,


(Должен сказать, что в этом вопросе я несколько радикальнее Павла. По моему мнению, например, в следующем примере — UB:
    i = (++i, 0);

Павел, если я все правильно помню, с этим согласен не был.)

D>что модификация одной переменной между точками следования — есть undefined behavior, пока это не отднозначно. Но то что это как минимум unspecified behavior — это точно.


Когда перестал действовать параграф 5/4 стандарта?
Re[6]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 07:55
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>>>    f(i++) + f(i++);
А>

А>>>Понятно, почему здесь UB?

B>>Здесь нет UB. Можно привести аргументацию?


А>Можно, конечно. Здесь нет точек следования, разделяющих две модификации переменной i.

А>Можете ли Вы такие точки следования указать?

А точки перед вызовом функции и прямо перед возвратом из нее. Я считаю, компилятор, если у него одной переменной дважды между точками следовования приводит к каким-то проблемам, не должен оптимизировать это выражение таким образом. То, что результат не определено — это вопросов не вызывает.
Re[6]: sequence point (по мотивам инкремента)
От: Bell Россия  
Дата: 04.06.04 07:56
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>
А>>>    f(i++) + f(i++);
А>

А>>>Понятно, почему здесь UB?

B>>Здесь нет UB. Можно привести аргументацию?


А>Можно, конечно. Здесь нет точек следования, разделяющих две модификации переменной i.

А>Можете ли Вы такие точки следования указать?
Могу:

1.9/17
When calling a function (whether or not the function is inline), 
there is a sequence point after the evaluation of all function arguments (if any) 
which takes place before execution of any expressions or statements in 
the function body...


Другое деле, что порядок вычисления этих аргументов не определен, но это не UB, а "unspecified behavior".
Любите книгу — источник знаний (с) М.Горький
Re[4]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 08:01
Оценка:
Здравствуйте, dupamid, Вы писали:

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


А>>Вот это новость!..


D>По С++'04 нет:


Просветите, пожалуйста, что такое С++'04. Уже принят TC2?

D>[i]5.18 Comma operator


А какова теперь редакция 1.9/18?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.