Этот неимоверно сложный MQL5! Поговорим об указателях.

Этот неимоверно сложный MQL5! Поговорим об указателях.

30 января 2024, 12:43
Alexey Volchanskiy
5
98

Всем привет!

Прикольный тут форум, 8 лет прошло, как я недоумевал, почему на форуме программистов в блогах нет раздела Программирование? Вот зашел, а воз и ныне там, опять приходится писать в Разное!


Возможно, начинающие не знают, но языки MQL4/5 не только крайне схожи между собой, но и созданы по образцу и подобию С++. Начнем с утверждения, что MQL4/5 схожи между собой. Я постоянно слышу на этом и других форумах стоны а-ля:«Я начал изучать MQL5, а он так сильно отличается от четверки, решил это дело забросить». В 100500-й раз повторяю, языки идентичны на 99%. Вы вечно путаете теплое с мягким, языки с библиотеками и API.

Надо четко понимать, что среда программирования для МТ4 и МТ5 состоит из трех частей:

1. Язык программирования. Это то, что можно посмотреть во встроенной справке в разделе «Справочник MQL5 / Основы языка / Синтаксис / Зарезервированные слова». Откройте точно такой же раздел для MQL4 и, как говорится, найдите разницу в картинках. Я беглым взглядом вижу, что в язык MQL5 добавили тип данных union (объединение), а в MQL4 его нет и уже не будет, так как язык больше не развивается. Грустить не стоит, union не так часто используется, его добавили из С++. В крестах Страуструп вообще наворотил много такого, что нормальный человек в жизни не будет использовать. Как говорил товарищ Грибоедов:«У вас батенька, Горе от ума!»

Сразу скажу главное отличие С++ от MQL4/5 — это работа с указателями. В плюсах, если мы не пишем управляемый код для .NET (CLI), указатель ссылается на конкретный адрес в программе. Да-да-да, я знаю, это не абсолютный физический адрес в ваших планках памяти DDRх. Винда создает для каждой программы свое виртуальное адресное пространство и программа считает, что она работает в отдельно выделенном ей компьютере. Именно поэтому мы можем создавать указатели для любых типов данных, в том числе и примитивных:


#include "pch.h"
#include <iostream>

int main()
{

        int i1 = 123;
        int* i2; //фактически, тут будет храниться адрес в памяти, по которому лежит что-то типа int
        i2 = &i1; //копируем в указатель адрес i1
        //выводим данные в окно консоли, std::cout это поток вывода, аналог функции Print в MQL.
        std::cout << "i1 = " << i1 << " *i2 = " << *i2 << " i2 = " << i2; // *i2 - это операция разименовывания указателя, то есть достаем данные по адресу i2

}


Вот что вывелось в консоли:
i1 = 123 *i2 = 123 i2 = 0056F944
Обратите внимание, i2 = 0056F944 — это тот виртуальный адрес, по которому живет указатель i2
И с этим адресом мы можем делать все что угодно, например инкрементировать. При этом мы попадем в область с неопределенными значениями. Добавим еще строку в конец проги.

std::cout << " *(++i2) = " << *(++i2) << " i2 = " << i2;

i1 = 123 *i2 = 123 i2 = 005CFCB4 *(++i2) = -858993460 i2 = 005CFCB8
Как видно, мы вышли адрес с какими-то странными данными -858993460. Скорее всего, это просто мусор в блоке данных.

Черт, вообще-то я хотел показать прикольный видеоролик с троллингом плюсов, но Остапа понесло. Я отключил в компиляторе VS2022 все оптимизации, добавим еще переменную i3 в конец, предположительно компилятор разместит ее по следующему адресу после i2, то есть по нашему *(++i2). Проверим?

int main()
{
        int i1 = 123;
        int* i2; //фактически, тут будет храниться адрес в памяти, по которому лежит что-то типа int
        int i3 = 987654321; // наверное компилятор разместит i3 сразу за первыми двумя переменными
        i2 = &i1; //копируем в указатель адрес i1

//выводим данные в окно консоли
        std::cout << "i1 = " << i1 << " *i2 = " << *i2 << " i2 = " << i2; // *i2 - это операция разименовывания указателя, то есть достаем данные по этому адресу
        std::cout << " *(++i2) = " << *(++i2) << " i2 = " << i2;
}

i1 = 123 *i2 = 123 i2 = 00AFF724 *(++i2) = -858993460 i2 = 00AFF728

Фокус не удался, узнаем хоть, куда компилятор положил i3 и на этом разойдемся.
std::cout << " *(++i2) = " << *(++i2) << " i2 = " << i2 << " &i3 = " << &i3;

i1 = 123 *i2 = 123 i2 = 010FFE30 *(++i2) = -858993460 i2 = 010FFE34 &i3 = 010FFE18

Как видим, компилятор посчитал нужным кинуть i3 по адресу 010FFE18, то есть перед, а не после всех. Ну, бог ему судья. Так вот, на MQL доступ к кишкам программы через указатели закрыт в целях безопасности. Вместо указателей там дескрипторы, которые не указывают на адреса в памяти, это надо четко понимать. Кому захочется поковыряться в кишочках, проект для VS в аттаче.



Файлы:
TestCPP2.zip  2155 kb