Ошибки, баги, вопросы - страница 3611

 
Alain Verleyen #:
Я дал объяснение, но вы его не поняли.

Из Вашего пояснения видно, что последовательность расчётов никак не регламентируется, а отдаётся на "откуп" компилятору.

Но в обсуждаемом примере чётко прослеживается последовательность, где можно (а может и нужно) учитывать математические приоритеты. Иначе нет возможности понимать в какой из очередных компиляций приоритеты будут расставлены иначе, чем в предыдущий раз, что приведёт к совершенно иным результатам при работе программы.

Я понимаю, что можно все расчёты сделать построчно шаг за шагом. Но оно стоит того?

 
Artyom Trishkin # :

Из Вашего пояснения видно, что последовательность расчётов никак не регламентируется, а отдаётся на "откуп" компилятору.

Но в обсуждаемом примере чётко прослеживается последовательность, где можно (а может и нужно) учитывать математические приоритеты. Иначе нет возможности понимать в какой из очередных компиляций приоритеты будут расставлены иначе, чем в предыдущий раз, что приведёт к совершенно иным результатам при работе программы.

Я понимаю, что можно все расчёты сделать построчно шаг за шагом. Но оно стоит того?

Может быть, я что-то упустил из-за перевода. Я перечитаю.
 

MQL использует ту же компиляцию, что и язык C.

        push    rbp
        mov     rbp, rsp
        sub     rsp, 16 
        mov     dword ptr [rbp - 4 ], 0
        mov     dword ptr [rbp - 8 ], 2               j=2 
        mov     eax, dword ptr [rbp - 8 ]             temp=j
        mov     dword ptr [rbp - 8 ], 5               j=5 
        imul    eax, eax, 5                           temp=temp*5   //[2*5] 
        mov     dword ptr [rbp - 8 ], eax             j=temp 
        mov     esi, dword ptr [rbp - 8 ]
        mov     rdi, qword ptr [rip + std::cout@GOTPCREL]
        call    std::ostream::operator<<( int )@PLT
        xor     eax, eax
        add     rsp, 16 
        pop     rbp
        ret
Компиляция MSVC/GCC (которая дает j=25):
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp- 4 ], 2                 j= 2 
        mov     DWORD PTR [rbp- 4 ], 5                 j= 5 
        mov     eax, DWORD PTR [rbp- 4 ]               temp=j
        imul    eax, eax                               temp=temp*temp //[ 5 * 5 ]
        mov     DWORD PTR [rbp- 4 ], eax               j=temp         //[ 25 ]
        mov     eax, DWORD PTR [rbp- 4 ]
        mov     esi, eax
        mov     edi, OFFSET FLAT:std::cout
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<( int )
        mov     eax, 0 
        leave
        ret

Оба варианта верны.

Вы НЕ МОЖЕТЕ полагаться на порядок выполнения или на то, как компилятор будет оценивать операнды.

 
Alain Verleyen #:
Вы НЕ МОЖЕТЕ полагаться на порядок выполнения или на то, как компилятор будет оценивать операнды.

Надеюсь, что оценка операндов в логических операциях всегда слева направо. Если это так, то это только благодаря brief estimate?

Очень распространенные примеры инициализации чего-то, где порядок оценки операндов критически важен:

bool a();
bool b();
bool c();
void doSomething();

bool initialize1()
  {
   return(a() && b() && c());
  }

bool initialize2()
  {
   if(!a() || !b())
      return(false);
   doSomething();
   return(c());
  }

void OnStart() {}
 
Vladislav Boyko #:
Очень распространенные примеры инициализации чего-то, где порядок оценки операндов критически важен:

Из того примера не очевидно, что порядок оценки операндов критически важен. Вот другой пример:

class A
  {
public:
   bool initialize();
   int get();
  };

class B
  {
public:
   bool initialize(int a);
   int get();
  };

class C
  {
public:
   bool initialize(int a, int b);
  };

bool f()
  {
   A a;
   B b;
   C c;
   // .get() should not be called before .initialize()
   return(a.initialize() && b.initialize(a.get()) && c.initialize(a.get(), b.get()));
  }
 
Vladislav Boyko # :

Надеюсь, что оценка операндов в логических операциях всегда слева направо. Если это так, то это только благодаря  brief estimate?

Очень распространенные примеры инициализации чего-то, где порядок оценки операндов критически важен:

Конечно, речь шла об арифметических операторах, а не о логических.
 

Интересно, почему для C#  Microsoft разделяет [Logical AND operator &, Logical OR operator |Logical exclusive OR operator ^] и bitwise версии этих операторов. При этом их C++ reference говорит только про bitwise версии (как и документация по MQL). Я слаб в побитовой арифметике. Logical и bitwise версии это одно и то же или нет? Будут ли в MQL побитовые операторы примененные к bool операндам работать так же, как это описывается по ссылкам, которые я привел?

 
Alexey Viktorov #:

Видимо я не смогу объяснить так, чтобы было понятно…

Вот смотри… Казалось бы переменной уже присвоено новое значение, ан нет, пока ещё j равна 2



Именно в этой иллюстрации явный баг. Переменная уже должна быть инициализирована новым значением, но отладчик отображает предыдущее.
 
Vladislav Boyko #:
Logical и bitwise версии это одно и то же или нет?

Совсем нет. Побитовые - это когда идёт работа с машинным представлением числа(или символа, ...) как с набором битовых флагов. В первом приближении это можно представить как структуры булевых переменных и логические операции над такими структурами.

 
Sergey Gridnev #:

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

А тут вариантов только два. Или разработчики исправят, или надо помнить о таких вариантах и не пытаться применять всяческие извращения которые зачастую приводят к непредсказуемому результату.