English 中文 Español Deutsch 日本語 Português
preview
От начального до среднего уровня: Директива Include

От начального до среднего уровня: Директива Include

MetaTrader 5Примеры |
360 6
CODE X
CODE X

Введение

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

В предыдущей статье, "От начального до среднего уровня: Операторы BREAK и CONTINUE", мы в основном сосредоточились на управлении потоком выполнения внутри циклов, использующих операторов WHILE и пару DO WHILE. Однако, хотя я полагаю, что вы уже достаточно подготовлены к объяснению цикла с оператором FOR, здесь я сделаю небольшую паузу на теме циклов. Это связано с тем, что перед тем, как перейти к другим операторам управления потоком, полезно сделать перерыв и изучить немного другие темы.

Поэтому в этой статье мы рассмотрим тему, которая может здорово помочь вам. По крайней мере, после того, как всё будет объяснено, я смогу начать показывать более сложный код, так как пока было довольно сложно создавать код без использования определенных ресурсов, доступных в MQL5. Хотя некоторые из вас могут подумать, что мне это далось легко, на самом деле писать код без использования определенных ресурсов очень сложно. Однако, теперь мы добавим несколько элементов к нашему списку достижений.

Ресурс, который я имею в виду, - это директивы компиляции. Без этих элементов мы сильно ограничены во многом, и нам придется писать гораздо больше кода, чем это было бы необходимо в реальной среде программирования.

Директивы компиляции, вопреки мнению многих, не делают код более запутанным, а наоборот. Его главная цель - упростить, упорядочить и облегчить работу с кодом и его модификацию. Но дело в том, что многие новички игнорируют их или не прилагают усилий, чтобы научиться правильно их использовать, возможно, потому что некоторые языки программирования не имеют этого ресурса в своем репертуаре. Примерами языков, в которых нет директив компиляции, являются JavaScript и Python. Хотя они довольно популярны среди непрофессиональных программистов, они не подходят для разработки некоторых типов приложений. Однако здесь мы хотим поговорить не об этих языках, а о MQL5. Давайте начнем с первой темы этой статьи.


Зачем нужны директивы компиляции?

Хотя директивы компиляции в MQL5 достаточны для большинства случаев, иногда мне кажется, что других директив не хватает. Это связано с тем, что MQL5, по сути, является очень хорошо проработанной модификацией языка C/C++. Но в C/C++ есть некоторые директивы, которых нет в MQL5. Одной из таких является #if, которая, хотя и может показаться неинтересной, в какие-то моменты очень помогает нам контролировать определенные части версии, над которой мы работаем.

Однако, хотя данная директива не присутствует в MQL5, по крайней мере, на момент написания статьи, ее отсутствие не будет проблемой в данном случае. Я упомянул этот момент только для того, чтобы вы (который, возможно, в будущем заинтересуется изучением C/C++) знали, что есть определенные аспекты, которые отличают C/C++ от MQL5. Хотя всё, или, по крайней мере, большая часть того, что будет показано, может также служить доступом в C/C++.

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

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

Однако такая практика необходима только в тех языках, где НЕТ директив компиляции. Языки с такими возможностями могут одновременно работать с несколькими мини-версиями одного и того же кода. И способ выбора между одной версией и другой - это именно использование продуманных и хорошо организованных директив.

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

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

Давайте теперь начнем с рассмотрения наиболее распространенной директивы в MQL5-кодах. Для этого перейдем к следующей теме.


Директива #INCLUDE

Скорее всего, именно с этой директивой компиляции вы будете чаще всего сталкиваться в кодах, особенно в MQL5 и в стилях C/C++. Почему так происходит? Это связано с тем, что большинство, или почти все опытные программисты НЕ предпочитают помещать всё в один код. Обычно (и со временем вы это поймете) опытные программисты делят свой код на небольшие блоки. Со временем они превращаются в библиотеку функций, процедур, структур и классов, организованных логическим образом. Это позволяет программировать очень быстро даже новые коды, с минимальным количеством модификаций, необходимых для адаптации оригинального, давно опубликованного кода к новому проекту.

А вы тем временем постоянно пишете код для выполнения одних и тех же действий.

Но я не собираюсь показывать вам, как организовать код таким образом, чтобы использовать преимущества данной директивы. На самом деле НИКТО не научит вас делать это, поскольку подобные вещи имеют смысл только тогда, когда разработчик тщательно и скрупулезно выбирает, где и что будет находиться. Однако, хотя я не буду показывать как всё это организовать, зато будет объяснено, как получить доступ к кодам, которые вы создали с такой тщательностью и самоотдачей. Именно в этом и заключается цель данной конкретной директивы: дать нам возможность получить доступ к разным элементам естественным и практичным способом.

Здесь нет потока исполнения, хотя есть детали, на которые следует обратить внимание. Однако мы будем рассматривать их постепенно, чтобы они были стопроцентно понятны.

Для начала возьмем один из кодов, которые были рассмотрены в предыдущих статьях. Это сделает всё более естественным. Для этого мы используем и настроим небольшой начальный код, как можно увидеть ниже:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     ulong value;
07. 
08.     Print("Factorial of 5: ", Factorial(5));
09.     Print("Factorial of 3: ", Factorial(3));
10.     Print(One_Radian());
11.     do
12.     {
13.         value = Tic_Tac();
14.         Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", value);
15.     }while (value < 3);
16.     Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", Tic_Tac(true));
17.     Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", Tic_Tac());
18. }
19. //+------------------------------------------------------------------+
20. double One_Radian()
21. {
22.     return 180. / M_PI;
23. }
24. //+------------------------------------------------------------------+
25. ulong Tic_Tac(bool reset = false)
26. {
27.     static ulong Tic_Tac = 0;
28. 
29.     if (reset)
30.         Tic_Tac = 0;
31.     else
32.         Tic_Tac = Tic_Tac + 1;
33. 
34.     return Tic_Tac;
35. }
36. //+------------------------------------------------------------------+
37. ulong Factorial(uchar who)
38. {
39.     static uchar counter = 0;
40.     static ulong value = 1;
41. 
42.     if (who) who = who - 1;
43.     else
44.     {
45.         counter = 0;
46.         value = 1;
47.     }
48.     while (counter < who)
49.     {
50.         counter = counter + 1;
51.         value = value * counter;
52.     };
53.     while (counter > who)
54.     {
55.         value = value / counter;
56.         counter = counter - 1;
57.     };
58.     counter = counter + 1;
59.     return (value = value * counter);
60. }
61. //+------------------------------------------------------------------+

Код 01

Вы должны обязательно понимать код 01, ведь это необходимое условие для того, чтобы мы могли двигаться дальше. Если вы не понимаете данный код, лучше вернуться к предыдущим статьям, ведь этот код очень прост и ни в коем случае не должен быть запутанным или сложным для понимания.

При выполнении этот код выдаст в терминале MetaTrader 5 следующее:


Рисунок 01

Мы делаем это только, чтобы проверить, действительно ли это работает. Поскольку мы видим, что это работает, мы можем начать говорить об использовании директивы компиляции. Возможно, мне следовало начать с другой директивы, но это не страшно, поскольку директива #include используется гораздо шире, чем все остальные, не имеет смысла начинать с другой. Так что давайте продолжим.

Первое, что нужно понять, прежде чем делать что-либо еще, - это как разработчик разделит разные элементы. Вам это может показаться банальным, но это далеко не так. Если вы не разработаете идеально подходящий для вас метод, то в конечном итоге столкнетесь с серьезными проблемами при создании новых кодов. Однако, если вы разработаете способ, который подойдет именно вам, вы добьетесь больших успехов.

Поскольку цель у нас только дидактическая, мы разделим всё на три разных файла. Каждый из них содержит функцию или процедуру, которая первоначально появилась в коде 01.

Учитывая это, можно подумать: "Хорошо, тогда я создам файлы". Но это не второй шаг, который нужно сделать, дорогой читатель. На самом деле, перед этим необходимо выполнить один предварительный шаг. Второй шаг заключается в ответе на следующий вопрос: В какой каталог поместить создаваемые файлы? Секундочку! Разве каталог не должен быть каталогом include? Это гораздо более личный вопрос, чем всё остальное, и это связано с тем, что не всегда лучшее место находится в каталоге include. Если вы не понимаете, о чем мы говорим, просто перейдите в папку MQL5 через MetaEditor, как показано на рисунке ниже:


Рисунок 02

Когда вы это сделаете, в каталоге MQL5 появится папка include. Данный каталог является каталогом по умолчанию для файлов создаваемого нами типа (заголовочные файлы). Однако, как уже говорилось выше, это не всегда лучший выбор. В зависимости от проекта или наших целей, размещение всех заголовочных файлов в каталоге include может в итоге навредить нам. Это связано с тем, что несколько отличающиеся версии одной и той же процедуры или функции могут конфликтовать с другими версиями, которые, возможно, находятся или должны находиться в данной папке include.

Однако многие могут поставить эту идею под сомнение, сказав что-то вроде: "Не могли ли бы мы создать подкаталоги, чтобы лучше организовать наши заголовочные файлы? Да, это действительно одно из самых распространенных решений, но даже при использовании подкаталогов в папке include бывают случаи, когда это нецелесообразно.

До того, как некоторые начнут волноваться, я покажу вам как это можно сделать. Это нужно для того, чтобы вы могли организовать коды наилучшим образом. Как мы уже говорили, никто не сможет научить вас, как именно это сделать, но, зная доступные варианты, вы сможете создать свою собственную организацию.

А сейчас давайте сделаем кое-что совершенно иное: мы создадим подкаталог в папке Scripts. В этом подкаталоге будет содержаться каждая из функций, показанных в коде 01. Однако, чтобы правильно разделить разные элементы, давайте разберемся с этим по частям, начав с решения номер 1.


Решение номер 1

Первое решение для разделения функций, показанных в коде 01, - это помещение каждой из них в заголовочный файл. Данные файлы будут находиться в папке в каталоге Scripts. Важная деталь: всегда старайтесь использовать расширение MQH для заголовочных файлов, которые создаются. Таким образом, будет проще определить, что это такое, просто заглянув в файловый менеджер операционной системы. Далее мы выполняем разделение. Оно разделяет файлы таким образом, что каждый из них содержит следующее.

1. //+------------------------------------------------------------------+
2. #property copyright "Daniel Jose"
3. //+------------------------------------------------------------------+
4. double One_Radian()
5. {
6.     return 180. / M_PI;
7. }
8. //+------------------------------------------------------------------+

Файл 01

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. ulong Tic_Tac(bool reset = false)
05. {
06.     static ulong Tic_Tac = 0;
07. 
08.     if (reset)
09.         Tic_Tac = 0;
10.     else
11.         Tic_Tac = Tic_Tac + 1;
12. 
13.     return Tic_Tac;
14. }
15. //+------------------------------------------------------------------+

Файл 02

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. ulong Factorial(uchar who)
05. {
06.     static uchar counter = 0;
07.     static ulong value = 1;
08. 
09.     if (who) who = who - 1;
10.     else
11.     {
12.         counter = 0;
13.         value = 1;
14.     }
15.     while (counter < who)
16.     {
17.         counter = counter + 1;
18.         value = value * counter;
19.     };
20.     while (counter > who)
21.     {
22.         value = value / counter;
23.         counter = counter - 1;
24.     };
25.     counter = counter + 1;
26.     return (value = value * counter);
27. }
28. //+------------------------------------------------------------------+

Файл 03

Один важный момент: после того, как будет сделано разделение, решение о том, где будут размещены элементы, будет зависеть от вас, равно как и названия каждого файла. Здесь нет никакого фиксированного правила. Вы вольны делать свой собственный выбор.

Теперь, когда коды были извлечены из кода 01 и помещены в отдельные файлы, в результате у нас получится код, похожий на этот:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     ulong value;
07. 
08.     Print("Factorial of 5: ", Factorial(5));
09.     Print("Factorial of 3: ", Factorial(3));
10.     Print(One_Radian());
11.     do
12.     {
13.         value = Tic_Tac();
14.         Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", value);
15.     }while (value < 3);
16.     Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", Tic_Tac(true));
17.     Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", Tic_Tac());
18. }
19. //+------------------------------------------------------------------+

Код 02

Отлично, он кажется намного проще, чем код 01. Так и есть, дорогой читатель. Однако, если вы попытаетесь скомпилировать код 02, то компилятор выдаст множество ошибок. Эти ошибки (можете их увидеть на изображении ниже) указывают на то, что компилятор не смог интерпретировать код.


Рисунок 03

На самом деле, проблема не в том, что компилятор не понял код, а в том, что компилятор НЕ ЗНАЕТ, как разрешить вызовы процедур и функций в коде. Как такое возможно? Вопреки тому, что многие думают о языке программирования, на самом деле в нем есть два основных компонента. Первый известен как стандартная библиотека. Она определяет функции, процедуры, зарезервированные слова, константы и другие элементы, которые мы используем для создания кода пользовательского уровня.

Вы, как программист, использующий разные языки, НЕ МОЖЕТЕ изменить работу стандартной библиотеки, но вы можете использовать то, что в нем определено, для создания собственных решений. Всё, что относится к стандартной библиотеке, можно использовать без каких-либо специальных операций. Однако всё выходящее за рамки этой библиотеки, нужно явно добавить в код. Это позволяет компилятору знать, как разрешить каждый из появляющихся вызовов. Поэтому, когда мы пытаемся скомпилировать код 02, который выглядит как код 01, мы не можем его скомпилировать.

Для этого вам нужно указать компилятору, какие файлы надо включать в компиляцию. Именно поэтому данная директива называется директивой компиляции и имеет довольно многозначительное название: #include. То есть включает этот файл во время компиляции данного кода. Вы понимаете, дорогой читатель?

Если вы действительно понимаете это, то сможете делать то, что раньше не могли. Даже когда вы пытались изучить программирование, существовали концепции, которые, казалось, не имели четкого и реального значения, но об этом мы поговорим в другой раз. Я не хочу вас путать переизбытком информации. Наша цель - понимать и правильно усвоить то, что объясняется в каждой из этих статей.

Если код 02 не может скомпилироваться именно из-за того, что компилятор не знает, как получить доступ к необходимой информации, то как мы можем решить эту проблему? Должны ли мы перейти к файлам, которые мы создали минуту назад, скопировать и вставить каждую из функций или процедур в код 02, чтобы снова стал похож на код 01? В конце концов, если код 01 можно скомпилировать, это означает, что он правильный. Но в этом решении нет особого смысла. Я видел другие коды, которые работают без копирования и вставки целых фрагментов в конечный код. Теперь мне интересно. Как решить эту проблему? Это самая простая часть: просто создаем нечто похожее на приведенный ниже код:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. #include "Tutorial\File 02.mqh"
06. #include "Tutorial\File 03.mqh"
07. //+------------------------------------------------------------------+
08. void OnStart(void)
09. {
10.     ulong value;
11. 
12.     Print("Factorial of 5: ", Factorial(5));
13.     Print("Factorial of 3: ", Factorial(3));
14.     Print(One_Radian());
15.     do
16.     {
17.         value = Tic_Tac();
18.         Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", value);
19.     }while (value < 3);
20.     Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", Tic_Tac(true));
21.     Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", Tic_Tac());
22. }
23. //+------------------------------------------------------------------+

Код 03

Теперь идет самое интересное. Когда мы попытаемся скомпилировать код 03, мы получим ответ, подобный приведенному ниже:


Рисунок 04

Иными словами, всё успешно! Но как это возможно? Причина кроется в строках четыре, пять и шесть кода 03. Эти строки можно размещать в любом месте кода. Однако по организационным причинам мы обычно помещаем их в начало. Бывают ситуации, когда они могут появиться в других местах, но это случается довольно редко и по очень специфическим причинам, которые здесь не уместно рассказывать. Тем не менее, возможность упорядочить всё в более чистом и практичном формате, - это замечательно.

Но здесь есть одна деталь, и очень важно, чтобы вы ее уловили, хотя бы на самом базовом уровне. Рассмотрим этот вопрос поподробнее в других статьях. Речь идет о том, как мы объявляем каждую из директив #include, присутствующих в коде 03.

На данном этапе я не собираюсь объяснять это. Тут желательно, чтобы вы обратились к документации. Дело в том, что если я попытаюсь объяснить это прямо сейчас, вы можете не понять, почему сделано именно так, как в коде 03. Хуже того, вы можете запутаться быстрее, чем разобраться в том, почему в одних случаях декларация выглядит одним образом, а в других - другим.

В документации можно найти это под заголовком: Включение файлов (#include). Но те, кто читал мои материалы на протяжении некоторого времени, прекрасно знают, что за тем, как объявлены строки четыре, пять и шесть в коде 03, есть своя причина.

В любом случае, при выполнении кода 03 мы получим тот же результат, что и на рисунке 01. Теперь мы продвигаемся ко второму типу решения. Но чтобы отделить его от первого, давайте перейдем к новой теме.


Решение номер 2

Второе решение следует принципу удобства использования. То есть мы создаем нечто, расширяющее возможности MQL5, чтобы генерировать новый код или делать это быстрее. Нередко некоторые программисты распространяют заголовочные файлы, которые уже присутствуют в установке MetaTrader 5, но были каким-то образом изменены. Лично я считаю такое распространение вполне обоснованным, поскольку некоторые из этих модификаций часто бывают очень интересными. Проблема заключается в том, чтобы решить, где мы будем размещать эти файлы.

И всё потому что MetaTrader 5 периодически обновляется. Если у нас есть один из таких модифицированных заголовочных файлов, даже если мы сделали его сами, и он оказался очень практичным и полезным для наших разработок, будет большой ошибкой оставить его где попало. Если данный файл находится в каталоге include папки MQL5, то при обновлении данных в MetaTrader 5 он может быть перезаписан. Если это произойдет, мы потеряем отличный заголовочный файл.

Однако у этой проблемы есть решение: переименование заголовочного файла. Также можно использовать то, что показано в предыдущей теме. В обоих случаях это сработает. Однако в данном случае мы изначально будем ограничены в некоторых аспектах. Например, будет сложнее получить доступ к заголовочным файлам, созданным вне текущего каталога. Не являясь чем-то невозможным, это немного сложнее из-за того, что нам придется кое-что сделать.

Именно по этой причине, когда мы хотим использовать один и тот же заголовочный файл в нескольких приложениях, совершенно не похожих друг на друга, предпочтительнее разместить в одном месте. В данном случае - в каталоге include. Однако не забывайте регулярно создавать резервные копии. В любом случае, лучше всего использовать инструмент для контроля версий.

В данном ситуации я предлагаю использовать GIT. Подробнее об этом инструменте можно узнать из другой моей статьи: GIT: Но что это? Это избавит нас от многих хлопот, если правильно изучать и использовать данный инструмент.

Теперь вернемся к нашему вопросу. Сейчас мы можем использовать те же файлы, что и в предыдущей теме, и поместить их в каталог include. С его помощью можно управлять двумя разными версиями одного и того же файла: одна будет легко доступна любому приложению, которое вы хотите создать, а другая будет доступна только определенному приложению. Чтобы прояснить ситуацию и продемонстрировать, что это возможно, мы изменим один из файлов, рассмотренных в предыдущей теме. Фактически, у нас будет две версии этого файла: одна доступна только для кода, который мы создадим здесь, а другая может быть использована любым другим кодом, который мы хотим реализовать. Этот файл показан ниже:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. double One_Radian()
05. {
06.     return 180. / M_PI;
07. }
08. //+------------------------------------------------------------------+
09. double ToRadians(double angle)
10. {
11.     return angle / One_Radian();
12. }
13. //+------------------------------------------------------------------+
14. double ToDegrees(double angle)
15. {
16.     return angle * One_Radian();
17. }
18. //+------------------------------------------------------------------+

Файл 04

Поскольку мы начинаем с самых азов, я не покажу некоторые вещи, которые мы могли бы сделать. Я остановлюсь на том, как можно работать с заголовочным файлом. Хорошо, теперь у нас есть два файла, содержащих две идентичные версии одной и той же функции, в данном случае функции One_Radians. Хотя сейчас это может показаться вам банальным и недостойным внимания, по мере того, как мы будем копать глубже и показывать новые характеристики, мы увидим, что такая ситуация может быть полезной. Но всему свое время.

Теперь мы хотим, чтобы файл 04 использовался вместо файла 01. Это связано с тем, что в нем содержатся другие функции, которые мы хотим использовать, благодаря приведенному ниже коду.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. #include "Tutorial\File 02.mqh"
06. #include "Tutorial\File 03.mqh"
07. //+------------------------------------------------------------------+
08. void OnStart(void)
09. {
10.     ulong value;
11. 
12.     Print("Factorial of 5: ", Factorial(5));
13.     Print("Factorial of 3: ", Factorial(3));
14.     Print(One_Radian());
15.     Print(ToRadians(90));
16.     do
17.     {
18.         value = Tic_Tac();
19.         Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", value);
20.     }while (value < 3);
21.     Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", Tic_Tac(true));
22.     Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", Tic_Tac());
23. }
24. //+------------------------------------------------------------------+

Код 04

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


Рисунок 05

Это говорит о том, что здесь кроется ошибка. Однако устранить данную ошибку довольно просто, хотя и требует от нас, как от программистов, определенного внимания. Это связано с тем, что мы можем работать с заголовочными файлами, в которых есть разные версии функции или процедуры с одним и тем же именем. И это самая сложная часть, которую вам придется освоить самостоятельно. Не существует универсального способа объяснить или научить, как с этим справиться, и причина проста: всё зависит от того, как вы организовали свое время. Помимо данного вопроса и учитывая, что наша цель - чисто дидактическая, решение довольно простое и понятное. На самом деле, сообщение об ошибке связано с отсутствием функции, которая должна находиться в строке 15. Поскольку данной функции нет ни в одном из включенных в код 04 заголовочных файлов, компиляция всегда будет неудачной. Поэтому мы должны указать компилятору, где находится нужный файл, содержащий код, необходимый для работы строки 15. Чтобы исправить это, просто изменим код на код 05, как показано ниже:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include <Tutorial\File 01.mqh>
05. #include "Tutorial\File 02.mqh"
06. #include "Tutorial\File 03.mqh"
07. //+------------------------------------------------------------------+
08. void OnStart(void)
09. {
10.     ulong value;
11. 
12.     Print("Factorial of 5: ", Factorial(5));
13.     Print("Factorial of 3: ", Factorial(3));
14.     Print(One_Radian());
15.     Print(ToRadians(90));
16.     do
17.     {
18.         value = Tic_Tac();
19.         Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", value);
20.     }while (value < 3);
21.     Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", Tic_Tac(true));
22.     Print(__FUNCTION__, " ", __LINE__, " Tic Tac: ", Tic_Tac());
23. }
24. //+------------------------------------------------------------------+

Код 05

Если заметили, изменения были очень незначительными. Однако данная модификация намеренно минимальна, чтобы показать вам, что необходимо практиковаться и посвятить себя пониманию того, как всё работает на практике. Когда мы попросим компилятор обработать код 05, результат будет таким:


Рисунок 06

Благодаря этому мы можем заметить, что файл, который мы включаем в четвертой строке, на самом деле находится в каталоге include. В приложении мы увидим иллюстрации, которые позволят вам понять, как всё должно быть организовано и структурировано на практике. Последнее, что будет показано в этой статье, это обзор результата выполнения кода 05:


Рисунок 07


Заключительные идеи

В этой статье мы узнали, как использовать одну из самых распространенных директив компиляции. Хотя мы сосредоточились лишь на одном аспекте, невозможно было бы в одной статье объяснить всё, что можно сделать с помощью данной директивы. Даже если бы мы написали еще несколько статей, посвященных исключительно этой директиве, мы всё равно не смогли бы охватить некоторые аспекты. Ведь для того, чтобы стать действительно хорошим программистом, недостаточно знать, как организовать код, чтобы получить результат. Также важно уметь организовывать свою собственную личность как программиста, создавая и организуя каталогами в заголовочных файлах наиболее интересные и полезные части кода, которые мы используем в своей повседневной работе.

Научить вас этому никто не сможет. Это то, что можно освоить только благодаря практике и времени, но для этого необходимо сделать первый шаг. Данная статья призвана помочь вам сделать этот первый шаг. Надеюсь, для вас было полезным. В следующей статье мы рассмотрим еще один оператор управления потоком. Увидимся позже!


Перевод с португальского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/pt/articles/15383

Прикрепленные файлы |
Anexo.zip (3.94 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (6)
Alexey Viktorov
Alexey Viktorov | 5 февр. 2025 в 07:22
Alexey Volchanskiy #:

Опять у автора бред. Цитата:« Но в C/C++ есть некоторые директивы, которых нет в MQL5. Одной из таких является #ifdef, которая, хотя и может показаться неинтересной, в какие-то моменты очень помогает нам контролировать определенные части версии, над которой мы работаем. »

#ifdef есть в MQL4 и MQL5 очень давно.

А ты зачем это читаешь?🤦‍♀️

Roman Shiredchenko
Roman Shiredchenko | 5 февр. 2025 в 07:27
Alexey Volchanskiy #:

Опять у автора бред. Цитата:« Но в C/C++ есть некоторые директивы, которых нет в MQL5. Одной из таких является #ifdef, которая, хотя и может показаться неинтересной, в какие-то моменты очень помогает нам контролировать определенные части версии, над которой мы работаем. »

#ifdef есть в MQL4 и MQL5 очень давно.

Alexey Viktorov #:

А ты зачем это читаешь?🤦‍♀️

У него ник в базе vDev - это его тема!!! 

Леха - давай скальпа тестить!!!! )

CODE X
CODE X | 5 февр. 2025 в 12:42
Alexey Volchanskiy # :

O autor está falando bobagem de novo. Citação: " Mas em C/C++ há algumas diretivas que não estão no MQL5. Um deles é o #ifdef, que, embora possa parecer desinteressante, em alguns pontos realmente nos ajuda a controlar certas partes da versão em que estamos trabalhando. »

#ifdef está no MQL4 e MQL5 há muito tempo.

Извини. Однако с моей стороны была допущена ошибка при ссылке на указание в тексте. Моей целью было сослаться на директиву #if, поскольку директива #ifdef является эквивалентом директивы #if defined, присутствующей в C и C++. Но чтобы обобщить это здесь, в MQL5, мы используем #ifdef, который также присутствует в C и C++. Опять же, целью будет ссылка на директиву #if, цель которой совершенно иная и которую можно использовать даже для проверки значений определений. Но из-за моей ошибки при написании я в итоге поставил #ifdef и не понял этого. Приношу извинения за эту оплошность с моей стороны. 👍

Alexey Volchanskiy
Alexey Volchanskiy | 5 февр. 2025 в 19:00
CODE X #:

Извини. Однако с моей стороны была допущена ошибка при ссылке на указание в тексте. Моей целью было сослаться на директиву #if, поскольку директива #ifdef является эквивалентом директивы #if defined, присутствующей в C и C++. Но чтобы обобщить это здесь, в MQL5, мы используем #ifdef, который также присутствует в C и C++. Опять же, целью будет ссылка на директиву #if, цель которой совершенно иная и которую можно использовать даже для проверки значений определений. Но из-за моей ошибки при написании я в итоге поставил #ifdef и не понял этого. Приношу извинения за эту оплошность с моей стороны. 👍

Ничего, у всех бывает )

Alexey Volchanskiy
Alexey Volchanskiy | 5 февр. 2025 в 19:01
Alexey Viktorov #:

А ты зачем это читаешь?🤦‍♀️

Случайно попалась статья, сайт выдал в ссылках.

Нейросети в трейдинге: Иерархический двухбашенный трансформер (Окончание) Нейросети в трейдинге: Иерархический двухбашенный трансформер (Окончание)
Мы продолжаем построение модели иерархического двухбашенного трансформера Hidformer, который предназначен для анализа и прогнозирования сложных многомерных временных рядов. В данной статье мы доведем начатую ранее работу до логического завершения с тестированием модели на реальных исторических данных.
Диалектический поиск — Dialectic Search (DA) Диалектический поиск — Dialectic Search (DA)
Представляем Диалектический Алгоритм (DA) — новый метод глобальной оптимизации, вдохновленный философской концепцией диалектики. Алгоритм использует уникальное разделение популяции на спекулятивных и практических мыслителей. Тестирование показывает впечатляющую производительность до 98% в задачах малой размерности и общую эффективность 57.95%. Статья объясняет эти показатели и представляет детальное описание алгоритма и результаты экспериментов на различных типах функций.
Возможности Мастера MQL5, которые вам нужно знать (Часть 30): Пакетная нормализация в машинном обучении Возможности Мастера MQL5, которые вам нужно знать (Часть 30): Пакетная нормализация в машинном обучении
Пакетная нормализация — это предварительная обработка данных перед их передачей в алгоритм машинного обучения, например, в нейронную сеть. При этом всегда следует учитывать тип активации, который будет использоваться алгоритмом. Мы рассмотрим различные подходы, которые можно использовать для извлечения выгоды с помощью советника, собранного в Мастере.
От начального до среднего уровня: Операторы BREAK и CONTINUE От начального до среднего уровня: Операторы BREAK и CONTINUE
В данной статье мы рассмотрим, как использовать операторы RETURN, BREAK и CONTINUE в цикле. Понимание того, что делает каждый из этих операторов в потоке выполнения цикла, очень важно для работы с более сложными приложениями. Представленные здесь материалы предназначены только для обучения. Ни в коем случае не рассматривайте его как окончательное приложение, целью которого не является изучение представленных концепций.