Особенности языка mql5, тонкости и приёмы работы - страница 317

 
Прошу подсказать, где я допускаю принципиальную ошибку в работе с макросами?
struct STRUCT
{
  int Value;
  
  void Func( int ) {}
};

#define MACROS(A) Struct##A

void OnStart()
{
  STRUCT Struct;

  MACROS(.Value) = 0; // Первая запись - OK.
  MACROS(.Func(0));   // Вторая запись - OK.

  MACROS(.Func(MACROS(.Value))); // Первая и вторая запись вместе - undeclared identifier.
}

Такое в других языках тоже работать не будет? Как правильно?


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


Приходится гадать, т.к. это не реализовано.

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Новая версия платформы MetaTrader 5 build 5320: сервисы в Библиотеке кодов и удобная работа с input в MQL5

fxsaber, 2025.09.25 16:14

Просьба это сообщение об ошибке в ME дополнять именем неопределенного идентификатора.
#define MACROS(A) A = 5;

void OnStart()
{
  MACROS(Tmp); // undeclared identifier Tmp
}

В сложных макросах очень сильно бы помогло выявить причины ошибки. Спасибо.

 
fxsaber #:
Подскажите, пожалуйста, где я допускаю фундаментальную ошибку в работе с макросами?

На других языках это тоже не работает? Как правильно поступить?

struct STRUCT
{
  int Value;

  void Func( int ) {}
};

#define   MACROS(A) Struct##A
#define  MACROS2(A) MACROS(A)

void OnStart()
{
  STRUCT Struct;

  MACROS(.Value) = 0; // Первая запись в порядке.
  MACROS(.Func(0));   // Вторая запись в порядке.

  MACROS2(.Func(MACROS2(.Value))); // Первая и вторая запись вместе - необъявленный идентификатор.
}

Решение: использовать макрос второго уровня (для перенаправления).

Это уже обсуждалось здесь и здесь.

 
amrali #:

Решение: использовать макрос второго уровня (для перенаправления).

Это уже обсуждалось здесь и здесь.

Спасибо большое!
 
Еще одна ситуация, когда необходимо "двойное расширение" макросов(__LINE__):
#define ST2(x) #x
#define STR(x) ST2(x)
#define  LOCATION __FILE__ " : " STR(__LINE__)

//#define LOCATION __FILE__ " : " __LINE__

void OnStart()
{
  Print("Error in ", LOCATION);
}
или напрямую:
#define  LOCATION __FILE__ + " : " + (string)__LINE__

Использование функции string() во время выполнения (но без оценки во время компиляции, как в первом примере).

 

Итак, что происходит в Print("Error in ", LOCATION)

Print("Ошибка в ", LOCATION) расширяется до Print("Ошибка в ", __FILE__ " : " STR(__LINE__))

STR(__LINE__) не имеет операции строкообразования, т.е. в ее расширении нет #x, но есть x, поэтому она должна оценить x и ввести значение __LINE__ в ST2 для строкообразования. Он расширяется до ST2(11) , который , в свою очередь, строчит число 11, поскольку использует #x.

Итак, с технической точки зрения:

  • При использовании одноуровневой индирекции ST2(x) #x строчит имя введенного макроса (например, " __LINE__")
  • но при использовании двойного слоя он строчит значение введенного макроса. (например: "11")
 

Итак, что происходит в Print("Error in ", LOCATION)

Print("Ошибка в ", LOCATION) расширяется до Print ("Ошибка в ",__FILE__ " : " STR(__LINE__))

STR(__LINE__) не имеет операции структуризации, т. е. в его расширении нет #x , но есть x , поэтому он должен оценить x и ввести значение __LINE__ в ST2 для структуризации. Он расширяется до ST2 (11), который , в свою очередь, строчит число 11, поскольку использует #x.

Итак, с технической точки зрения:

  • При использовании одноуровневой индирекции ST2 (x) #x строчит имя введенногомакроса ( например, " __LINE__")
  • но при использовании двойного слоя он строчитзначение введенногомакроса. (например: "11")
 
amrali #:



    #define __SOURCE__ __FILE__ + " (" + (string)__LINE__ + ") " + __FUNCTION__
     

    Форум о трейдинге, автоматизированных торговых системах и тестировании торговых стратегий

    Особенности языка mql5, тонкости и хитрости

    amrali, 2025.11.04 11:40

    struct STRUCT
    {
      int Value;
    
      void Func( int ) {}
    };
    
    #define   MACROS(A) Struct##A
    #define  MACROS2(A) MACROS(A)
    
    void OnStart()
    {
      STRUCT Struct;
    
      MACROS(.Value) = 0; // Первая запись в порядке.
      MACROS(.Func(0));   // Вторая запись в порядке.
    
      MACROS2(.Func(MACROS2(.Value))); // Первая и вторая запись вместе - необъявленный идентификатор.
    }
    

    Решение: использовать макрос второго уровня (для перенаправления).

    Это уже обсуждалось здесь и здесь.

    Кроме того, для отладки расширений макросов в MQL:
    //+------------------------------------------------------------------+
    //| Выведите расширение макроса с помощью оператора Stringizing # |
    //+------------------------------------------------------------------+
    #define  STRINGIFY(s) #s
    #define EXPAND_MACRO(macro)  Print(STRINGIFY(macro))
    
    struct STRUCT
    {
      int Value;
    
      void Func( int ) {}
    };
    
    #define   MACROS(A) Struct##A
    #define   MACROS2(A) MACROS(A)
    
    void OnStart()
    {
      STRUCT Struct;
    
      //MACROS(.Func(MACROS(.Value))); //Ошибка компиляции
      MACROS2(.Func(MACROS2(.Value))); // OK.
    
      EXPAND_MACRO(MACROS(.Func(MACROS(.Value))));
      EXPAND_MACRO(MACROS2(.Func(MACROS2(.Value))));
    }
    

    Вывод:

    2025.11.07 12:46:29.155 Nested (EURUSD,H1)      Struct.Func(MACROS(.Value))
    2025.11.07 12:46:29.155 Nested (EURUSD,H1)      Struct.Func(Struct.Value)
    
     

    Если во время оптимизации нажать на Стоп, то дескрипторы прерванных проходов остаются открытыми, т.к. выполнение кода жестко прерывается, не давая выполниться логике закрытия дескрипторов - CloseHandle.

    Более того, такая ситуация может возникнуть во время дебага, когда во время отладки идет закрытие дебага. В общем, есть сценарии, в которых не закрываются дескрипторы.


    Долго искал в интернете способы закрытия дескрипторов. В частности, в случае использования File Mapping.

    Нашел только формулировку такой же проблемы без ответа.


    Например, если процесс был прерван до CloseHandle, то такая функция всегда будет возвращать true на следующих запусках.

      static bool IsExist( const string Name = __FILE__ )
      {
        const HANDLE handle = kernel32::OpenFileMappingW(FILE_MAP_ALL_ACCESS, 0, Name);
      
        if (handle)
          kernel32::CloseHandle(handle);
    
        return((bool)handle);
      }


    Возможно ли как-то освобождать память/файл в случае, если висят открытые дескрипторы? Сейчас проблема решается только перезагрузкой процесса - Терминала.

    CreateFileMapping() returning "already exists" even after reboot; how to remove old Named Shared Memory?
    CreateFileMapping() returning "already exists" even after reboot; how to remove old Named Shared Memory?
    • 2012.10.03
    • Blake Senftner
    • stackoverflow.com
    I have a series of Slave exe's controlled by a Master exe via usage of Named Shared Memory created with CreateFileMapping() and MapViewOfFile(). I was debugging the Master via Visual Studio, and when I got what I needed I simply told Visual Studio to "stop debugging". Bad move, because that Named Shared Memory was left active, and it is still...
     
    fxsaber # :
    Возможно ли как-то освобождать память/файл в случае, если висят открытые дескрипторы? Сейчас проблема решается только перезагрузкой процесса - Терминала.
    Можно ли повторно использовать существующий Handle?