Почему Print печатает задом наперед?

 

Вот такое встретилось, build 1881. Что бы это значило?

#define ARR_SIZE 8

void OnStart()
{
    int iArr[ARR_SIZE] = {1,2,3,4,5,6,7,8};   
    int i = 0;
    Print("iArr[i++]"," ", iArr[i++], " i=", i, ", ", iArr[i++], " i=", i, ", ", iArr[i++], " i=", i, ", ", iArr[i++], " i=", i, ", ", iArr[i++], " i=", i, ", ", iArr[i++], " i=", i, ", ",
        iArr[i++],  " i=", i, ", ", iArr[i]);
}

2018.08.05 20:40:38.345 TestArray (GBPUSD,M1) iArr[i++] 7 i=6, 6 i=5, 5 i=4, 4 i=3, 3 i=2, 2 i=1, 1 i=0, 1


 
Alexey Volchanskiy:

Вот такое встретилось, build 1881. Что бы это значило?

2018.08.05 20:40:38.345 TestArray (GBPUSD,M1) iArr[i++] 7 i=6, 6 i=5, 5 i=4, 4 i=3, 3 i=2, 2 i=1, 1 i=0, 1


А 8 где?

 
Evgeniy Zhdan:

А 8 где?

То-то и оно, могу только подозревать, потому, что в конце принта у последнего элемента массива не проставлен i++, а просто i. Да изврат какой-то, буду в СД писать попозже, если никто не ответит.

 
Alexey Volchanskiy:

Вот такое встретилось, build 1881. Что бы это значило?

2018.08.05 20:40:38.345 TestArray (GBPUSD,M1) iArr[i++] 7 i=6, 6 i=5, 5 i=4, 4 i=3, 3 i=2, 2 i=1, 1 i=0, 1


Припоминаю, что при вызовах функций конкатенации строк с несколькими аргументами перед вызовом операции конкатенации в ее аргументах, если есть выполнимые команды, они выполняются в порядке справа налево по аргументам, то есть сначала в самом последнем, затем в предыдущем и т.д. Значит, и в Print так же, i для самого левого аргумента (операнда) имеет наибольшее значение, после выполнения всех i++.
 
Vladimir:
Припоминаю, что при вызовах функций конкатенации строк с несколькими аргументами перед вызовом операции конкатенации в ее аргументах, если есть выполнимые команды, они выполняются в порядке справа налево по аргументам, то есть сначала в самом последнем, затем в предыдущем и т.д. Значит, и в Print так же, i для самого левого аргумента (операнда) имеет наибольшее значение, после выполнения всех i++.

На чем основано данное умозаключение?

Поиск в гугле по запросу " при вызовах функций конкатенации строк с несколькими аргументами" такого не приводит.

 
Evgeniy Zhdan:

На чем основано данное умозаключение?

Поиск в гугле по запросу " при вызовах функций конкатенации строк с несколькими аргументами" такого не приводит.

Я тоже такого не встречал ни в С++, ни в MQL4/5.

Еще немного добавил принтов

#define ARR_SIZE 8

void OnStart()
{
    int iArr[ARR_SIZE] = {1,2,3,4,5,6,7,8};   
    int i = 0;
    Print("iArr[i++]","   ", iArr[i++], " i=", i, ", ", iArr[i++], " i=", i, ", ", iArr[i++], " i=", i, ", ", iArr[i++], " i=", i, ", ", iArr[i++], " i=", i, ", ", iArr[i++], " i=", i, ", ",
        iArr[i++],  " i=", i, ", ", iArr[i]);
    i = 0;
    Print("iArr[i]","   ", iArr[i], " i=", i++, ", ", iArr[i], " i=", i++, ", ", iArr[i], " i=", i++, ", ", iArr[i], " i=", i++, ", ", iArr[i], " i=", i++, ", ", iArr[i], " i=", i++, ", ",
        iArr[i],  " i=", i++, ", ", iArr[i]);
    Print("iArr[0..7]","   ",iArr[0], ", ",iArr[1], ", ",iArr[2], ", ",iArr[3], ", ",iArr[4], ", ",iArr[5], ", ",iArr[6], ", ",iArr[7]);
    
}

2018.08.05 22:02:58.218 TestArray (GBPUSD,M1) iArr[i++]   7 i=6, 6 i=5, 5 i=4, 4 i=3, 3 i=2, 2 i=1, 1 i=0, 1

2018.08.05 22:02:58.218 TestArray (GBPUSD,M1) iArr[i]   8 i=6, 7 i=5, 6 i=4, 5 i=3, 4 i=2, 3 i=1, 2 i=0, 1

2018.08.05 22:02:58.218 TestArray (GBPUSD,M1) iArr[0..7]   1, 2, 3, 4, 5, 6, 7, 8


 
Vladimir:
Припоминаю, что при вызовах функций конкатенации строк с несколькими аргументами перед вызовом операции конкатенации в ее аргументах, если есть выполнимые команды, они выполняются в порядке справа налево по аргументам, то есть сначала в самом последнем, затем в предыдущем и т.д. Значит, и в Print так же, i для самого левого аргумента (операнда) имеет наибольшее значение, после выполнения всех i++.

Да, верно.

Значения помещаются в стек вызова функций с последнего параметра.

Не надо строить сложные взаимозависимые вычисляемые выражения в параметрах.


В С++ похожие приколы будут. Причем в зависимости от оптимизатора Debug/Release сборок могут выдаваться разные значения.

Пример:

int _tmain(int argc, _TCHAR* argv[])
  {
   int      iArr[8] ={ 1,2,3,4,5,6,7,8 };
   volatile int i=0;

   printf("Results: %d %d\n",iArr[i++],iArr[i++]);

   return(0);
  }

В VS2017:

в релизе оптимизатор посчитал себя умным(да, это явная ошибка компилятора!) даже при наличии volatile квалификатора и выдал одинаковый результат:
Results: 1 1

в дебаг сборке оптимизатора нет и вычисления идут как задумал(пусть даже он наоборот думал) автор:
Results: 2 1

Как видите, в C++ тоже обратный порядок. Как и в MQL5.

 

Это же классическое правило С.

Аргументы в функцию передаются с конца.

void OnStart()
{
   int x = 7;
   Print(++x, " ", ++x);
}
 
Roffild:

Это же классическое правило С.

по стандарту С++ порядок вычисления аргументов UB

 
Такие приколы бывают. Например в VB. Поэтому за правило наверное уже у многих - предпочтительнее обратный порядок перебора элементов массива...
 
Renat Fatkhullin:

Да, верно.

Значения помещаются в стек вызова функций с последнего параметра.

Не надо строить сложные взаимозависимые вычисляемые выражения в параметрах.

В С++ похожие приколы будут. Причем в зависимости от оптимизатора Debug/Release сборок могут выдаваться разные значения.

Пример:

В VS2017:

Как видите, в C++ тоже обратный порядок. Как и в MQL5.

Все это тяжелое наследие Си, когда здравый смысл приносился в угоду производительности. Фактически, все что надо, это чтобы компилятор собирал выходную строку Print не так, как ее вычисляемые параметры положили в стек, а как принято читать/писать в западной культуре - слева направо. Это правило явно придумали какие-то арабские программисты, ведь у них все наоборот - справа налево )) Значит, в случае с вычисляемыми выражениями надо формировать строку самому, например такими путями (это я для новичков, конечно):

#define ARR_SIZE 8

void OnStart()
{
    int iArr[ARR_SIZE] = {1,2,3,4,5,6,7,8};   
    string str = "iArr string formed by a cycle: ";
    for(int n = 0; n < ARR_SIZE; n++)
    {
        str += IntegerToString(iArr[n]);
        str += (n < ARR_SIZE - 1) ? ", " : "";
    }    
    Print(str);    

    i = 0;
    Print("iArr[i++] with concatente   " + iArr[i++] + " i=" + i + ", " + iArr[i++] + " i=" + i + ", "+ iArr[i++] + " i=" + i + ", "+ iArr[i++] + " i=" + i + ", " + iArr[i++] + " i=" + i + ", "+ iArr[i++] + " i=" + i +
        ", " + iArr[i++] + " i=" + i + ", " + iArr[i]);

}

2018.08.06 03:35:47.181 TestArray (EURUSD,M5)   iArr string formed by a cycle: 1, 2, 3, 4, 5, 6, 7, 8
2018.08.06 03:35:47.181 TestArray (EURUSD,M5)   iArr[i++] with concatente   1 i=1, 2 i=2, 3 i=3, 4 i=4, 5 i=5, 6 i=6, 7 i=7, 8

Во втором случае имеем 15 варнингов "implicit conversion from 'number' to 'string'", а если вставлять везде IntegerToString(iArr[i++]) и IntegerToString(i), то строка станет совсем нечитаема.

Надо еще проверить на "кошерном" C#, неужели и там так же?