Здравствуйте, seejay, Вы писали:
S>Не могу понять, почему для int* порядок вычисления аргументов оператора == один, а для структуры другой.
Компилятор имеет право выбирать любой порядок вычислений операндов оператора==.
S> if (&pi == &++pi)
Тут ты сравниваешь адрес переменной pi с адресом переменной pi. Невероятно, но адрес переменной не зависит от её значения. Такое условие будет истинно всегда, независимо от выбранного порядка.
Здравствуйте, seejay, Вы писали:
S>Не могу понять, почему для int* порядок вычисления аргументов оператора == один, а для структуры другой.
Не могу сослаться на конкретный пункт стандарта, но то в какой последовательности компилятору вычислять левую и правую часть сравнения стандарт не оговаривает,
тут действуют те же правила что и при передачи параметров в функцию (по факту тут и есть что то типа вызова оператора сравнения).
Например ниже приведенный пример демонстрирует следующее:
— сперва применяется инкримент для всех переменных условия
— потом там всякие арифметические операции...
— потом берутся значения по адресам опять же для всех переменных условия
— и потом применяется посткримент, опять для всех переменных условия
#include <iostream>
int main()
{
int m[10] = {0,1,2,3};
{
int * pi_0 = m;
std::cout << ((* pi_0 == *++pi_0) ? "ok\n" : "not ok\n"); // № 1
}
{
int * pi_0 = m;
std::cout << ((*++pi_0 == * pi_0) ? "ok\n" : "not ok\n"); // № 2
}
{
int * pi_0 = m;
std::cout << ((* pi_0 == *pi_0++) ? "ok\n" : "not ok\n"); // № 3
}
{
int * pi_0 = m;
std::cout << ((*pi_0++ == * pi_0) ? "ok\n" : "not ok\n"); // № 4
}
{
int * pi_0 = m;
std::cout << ((* pi_0 == *(pi_0+sizeof(*++pi_0))) ? "ok\n" : "not ok\n"); // № 5
}
{
int * pi_0 = m;
std::cout << ((*(pi_0+sizeof(*++pi_0)) == * pi_0) ? "ok\n" : "not ok\n"); // № 6
}
{
int * pi_1 = m;
int * pi_2 = m;
++pi_2;
std::cout << ((* pi_1 == * pi_2) ? "ok\n" : "not ok\n"); // № 7
}
return 0;
}
Здравствуйте, _niko_, Вы писали:
__>Здравствуйте, seejay, Вы писали:
S>>Не могу понять, почему для int* порядок вычисления аргументов оператора == один, а для структуры другой.
__>...
С примерами №5 и №6 осечка вышла
#include <iostream>
int main()
{
int m[10] = {0,1,2,3,4,5,6,7,8,9};
{
int * pi_0 = m;
std::cout << ((* pi_0 == *++pi_0) ? "ok\n" : "not ok\n"); // № 1
}
{
int * pi_0 = m;
std::cout << ((*++pi_0 == * pi_0) ? "ok\n" : "not ok\n"); // № 2
}
{
int * pi_0 = m;
std::cout << ((* pi_0 == *pi_0++) ? "ok\n" : "not ok\n"); // № 3
}
{
int * pi_0 = m;
std::cout << ((*pi_0++ == * pi_0) ? "ok\n" : "not ok\n"); // № 4
}
{
int * pi_0 = m;
std::cout << ((* pi_0 == *(++pi_0 + 1)) ? "ok\n" : "not ok\n"); // № 5
}
{
int * pi_0 = m;
std::cout << ((*(++pi_0 + 1) == * pi_0) ? "ok\n" : "not ok\n"); // № 6
}
{
int * pi_1 = m;
int * pi_2 = m;
++pi_2;
std::cout << ((* pi_1 == * pi_2) ? "ok\n" : "not ok\n"); // № 7
}
return 0;
}
Здравствуйте, seejay, Вы писали:
S>Не могу понять, почему для int* порядок вычисления аргументов оператора == один, а для структуры другой.
Потому что для int* у тебя неопределённое поведение, а для структуры — неспецифицированное.
В случае структуры получается, условно говоря, f(g()) == f()
Какие функции в каком порядке вызовутся — это личное дело компилятора (хотя в дебаге, вероятнее всего, сперва будет правая f(), затем левая g(), затем левая f()).
А поскольку они ещё и с побочными эффектами и влияют друг на друга, то может получиться что угодно.
В случае голого указателя вообще говорить не о чем, это классика UB: чтение и изменение вперемешку. Ничем не хуже классики i + i++.
int m[10] = {0,1,2,3};
int *pi = m;
if (&pi == &++pi)
std::cout << "pint ok";
К>В случае голого указателя вообще говорить не о чем, это классика UB: чтение и изменение вперемешку. Ничем не хуже классики i + i++.
Да нет же. Изменяется значение переменной, а читается ее адрес.
Кроме того, на сколько я помню, "классикой" (до отмены точек следования) было что-то вроде "i = i++" — т.е. повторное изменение переменной между соседними точками следования.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
К>>В случае голого указателя вообще говорить не о чем, это классика UB: чтение и изменение вперемешку. Ничем не хуже классики i + i++. R>Да нет же. Изменяется значение переменной, а читается ее адрес.
А, точно! Прощёлкал глазами.
R>Кроме того, на сколько я помню, "классикой" (до отмены точек следования) было что-то вроде "i = i++" — т.е. повторное изменение переменной между соседними точками следования.
Ну, если уж о классике говорить, то i++ + ++i
А как нынешний стандарт разруливает такие конструкции? Ну, кроме того, что точки следования по-другому называются.
Один же леший, неопределённое поведение.
Причём, это ведь не издевательство компиляторостроителей над новичками, а суровая правда жизни:
int foo(int& i, int& j) { return i++ + ++j; } // можно оптимизировать как угодно (казалось бы...)int bar(int& i) { foo(i, i); }
Здравствуйте, watchmaker, Вы писали:
W>Тут ты сравниваешь адрес переменной pi с адресом переменной pi. Невероятно, но адрес переменной не зависит от её значения. Такое условие будет истинно всегда, независимо от выбранного порядка.