结构体

当将 MQL 程序与外部系统集成时,尤其是当通过互联网发送或接收数据时,有必要将数据结构体转换为字节数组。为此,MQL5 API 提供了两个函数:StructToCharArrayCharArrayToStruct

在两种情况下,假定结构体仅包含简单 内置类型,也就是除了 和动态 数组外的所有内置类型。一个结构体也可能包含其它简单结构体。不允许包含类对象和指针。这种结构体也称为简单旧数据 (POD)。

bool StructToCharArray(const void &object, uchar &array[], uint pos = 0)

StructToCharArray 函数将 POD 结构体 object 复制到 uchar 类型的 array 数组。或者,使用参数 pos 可指定在数组中放置字节的开始位置。默认情况下,复制从数组开始位置进行,如果其当前大小不足以容纳整个结构体,则动态数组将自动增加大小。

函数返回成功指示器 (true) 或错误 (false)。

我们使用脚本 ConversionStruct.mq5 检查其执行。我们创建新的结构体类型 DateTimeMsc,其包括标准结构体 MqlDateTimemdt 字段)和 int 类型的附加字段 msc 以存储毫秒。

struct DateTimeMsc
{
   MqlDateTime mdt;
   int msc;
   DateTimeMsc(MqlDateTime &initint m = 0) : msc(m)
   {
      mdt = init;
   }
};

OnStart 函数中,我们将测试值 datetime 转换为我们的结构体,然后转换为字节数组。

MqlDateTime TimeToStructInplace(datetime dt)
{
   static MqlDateTime m;
   if(!TimeToStruct(dtm))
   {
      // the error code, _LastError, can be displayed
      // but here we just return zero time
      static MqlDateTime z = {};
      return z;
   }
   return m;
}
 
#define MDT(TTimeToStructInplace(T)
 
void OnStart()
{
   DateTimeMsc test(MDT(D'2021.01.01 10:10:15'), 123);
   uchar a[];
   Print(StructToCharArray(testa));
   Print(ArraySize(a));
   ArrayPrint(a);
}

我们将在日志中获得以下结果(数组被重新设置格式,带有附加换行符以强调字节与每个字段的对应性):

   true
   36
   229   7   0   0
     1   0   0   0
     1   0   0   0
    10   0   0   0
    10   0   0   0
    15   0   0   0
     5   0   0   0
     0   0   0   0
   123   0   0   0

 

bool CharArrayToStruct(void &object, const uchar &array[], uint pos = 0)

CharArrayToStruct 函数将 uchar 类型的 array 数组复制到 POD 结构体 object。使用 pos 参数可指定在数组中开始读取字节的位置。

函数返回成功指示器 (true) 或错误 (false)。

继续相同示例 (ConversionStruct.mq5),我们可从字节数组还原原始日期和时间。

void OnStart()
{
   ...
   DateTimeMsc receiver;
   Print(CharArrayToStruct(receivera));                 // true
   Print(StructToTime(receiver.mdt), "'"receiver.msc);  // 2021.01.01 10:10:15'123
}