程序库: TypeToBytes - 页 3

 
 
三行相同的内容
Color = (color)ColorToARGB(Color, Alpha);

Color = (color)((Color & 0xFFFFFF) + (Alpha << 24));

_W(Color)[3] = Alpha;
 

关于交易、自动交易系统和测试交易策略的论坛

关于 MQL4 的任何新手问题,算法和代码的帮助和讨论

fxsaber, 2017.03.07 13:55

#include <TypeToBytes.mqh>

template <typename T>
void Swap( T &Value1, T &Value2 )
{
  const T Tmp = Value1;
  
  Value1 = Value2;
  Value2 = Tmp;
}

// 对任意简单类型的数组进行排序
template <typename T>
bool MyArraySort( T &Array[] )
{
  if (!ArraySort(Array))
  {
    const int Size = ArraySize(Array);
    
    for (int i = 0; i < Size - 1; i++)
    {
      const T Tmp = Array[i];
      
      for (int j = i + 1; j < Size; j++)
        if (_R(Tmp) == Array[j]) // TypeToBytes.mqh
        {
          Swap(Array[i + 1], Array[j]);
          
          i++;
        }
    }      
  }
  
  return(true);
}
 
还添加了对数组进行逐字节操作的功能
// 使用数组
  short Array[] = {1, 2, 3};
  ArrayPrint(_R(Array).Bytes);           // 逐字节打印 Array 数组的表示形式

  PRINT((_R(Array) == _R(Array).Bytes))  // 确保逐字节数组比较正常工作。

  _W(Color) = Array;                     // 逐字节将 Array 数组写入颜色
  PRINT(Color)                           // 确保颜色现在是 C'1,0,2'。
  ArrayPrint(_R(Color).Bytes);           // 逐字节打印颜色表示法

  uchar Array2[];
  ArrayCopy(Array2, _R(Tick).Bytes);     // 将 Tick 的字节表示写入 Array2
  PRINT((_R(Tick) == Array2))            // 确保 Tick 和 Array2 一个字节一个字节地匹配

  MqlTick Tick2 = {0};
  _W(Tick2) = Array2;                    // 将 Array2 数组写入 Tick2
  PRINT((_R(Tick) == Tick2))             // 确保 Tick 和 Tick2 匹配。

  int Array3[] = {INT_MIN, INT_MAX};
  ArrayPrint(_R(Array3).Bytes);          // 逐字节打印 Array3 数组的表示形式
  ArrayPrint(_R(Array).Bytes);           // 逐字节打印 Array 数组的表示形式

  _ArrayCopy(Array3, Array);             // 将 Array 数组逐字节复制到 Array3 数组中
  ArrayPrint(_R(Array3).Bytes);          // 确保 Array3 数组的字节表示法与 Array2 数组的字节表示法相匹配。
 
还添加了对字符串进行逐字节操作的功能
// 处理字符串
  string Str = "abcd";

  _W(i) = Str;                           // 将字符串一个字节一个字节地写入 (int)i

  PRINT((_R(i) == Str))                  // 逐字节比较 int 和 sring

  ArrayPrint(_R(i).Bytes);               // 查询字节 i
  ArrayPrint(_R(Str).Bytes);             // 查看 Str 字节

  PRINT(_R(Str)[(short)1])               // 在 Str 中通过混合 1 取得短值

  PRINT(Str)
  _W(Str)[2] = "98765";                  // 逐字节将字符串写入偏移量 2 处的字符串
  PRINT(Str)

  string StrArray[] = {"123", "45", "6789"};
  _W(Str) = StrArray;                    // 将字符串数组写入字符串
  PRINT(Str)

  _W(Str)[3] = (uchar)0;                 // 在偏移量 3 的字节中写入 0,从而切断字符串(长度 - 3 个 ANSI 字符(4 字节))。
  PRINT(Str);
 

关于交易、自动交易系统和测试交易策略的论坛

库:无需 DLL 的文件映射

fxsaber, 2017.04.03 16:07

感谢作者提供的库!

我制作了用于传输任何数据的函数。下面的脚本以 ticks 为例展示了它们的工作情况

#include <MemMapLib.mqh>
#include <TypeToBytes.mqh>

// 为数据分配指定长度的内存 
template <typename T>
bool GetFileMemory( CMemMapFile* &FileMemory, const int Amount, const string FileName = "Local\\test" )
{
  FileMemory = new CMemMapFile;
    
  return(FileMemory.Open(FileName, sizeof(T) * Amount + sizeof(int) + HEAD_MEM, modeCreate) == 0);
}

// 将数据写入内存
template <typename T>
void DataSave( CMemMapFile* FileMemory, const T &Data[], const bool FromBegin = true  )
{
  const int Size = ArraySize(Data) * sizeof(T);
  uchar Bytes[];
  
  _ArrayCopy(Bytes, _R(Size).Bytes);              // 记录数量 
  _ArrayCopy(Bytes, _R(Data).Bytes, sizeof(int)); // 记录数据

  if (FromBegin)
    FileMemory.Seek(0, SEEK_SET);

  FileMemory.Write(Bytes, ArraySize(Bytes)); // 将所有内容转入内存
  
  return;
}

// 从内存中读取数据
template <typename T>
int DataLoad( CMemMapFile* FileMemory, T &Data[], const bool FromBegin = true )
{
  if (FromBegin)
    FileMemory.Seek(0, SEEK_SET);

  uchar Bytes[];
          
  FileMemory.Read(Bytes, sizeof(int));  // 从内存中读取数据量 
  FileMemory.Read(Bytes, _R(Bytes)[0]); // 获取数据本身

  _ArrayCopy(Data, Bytes);              // 将数据转入数组
  
  return(ArraySize(Data));
}

#define  AMOUNT 1000

#define  TOSTRING(A) #A + " = " + (string)(A) + " "

// 标记传输示例
void OnStart()
{  
  CMemMapFile* FileMemory;
  
  if (GetFileMemory<MqlTick>(FileMemory, AMOUNT))
  {
    MqlTick Ticks4Save[];    
    CopyTicks(_Symbol, Ticks4Save, COPY_TICKS_INFO, 0, AMOUNT);
    
    DataSave(FileMemory, Ticks4Save);
    
    MqlTick Ticks4Load[];    
    
    if (DataLoad(FileMemory, Ticks4Load) > 0)    
      Print(TOSTRING((_R(Ticks4Save) == Ticks4Load)) +
            TOSTRING(ArraySize(Ticks4Save)) +
            TOSTRING(ArraySize(Ticks4Load)));
     
    FileMemory.Close();   
  }
  
  delete FileMemory;
}


结果

(_R(Ticks4Save)==Ticks4Load) = true ArraySize(Ticks4Save) = 1000 ArraySize(Ticks4Load) = 1000

创新成果的实际应用实例。

 
#include <TypeToBytes.mqh>

// 将所有数组字符串合并为一个字符串
string StringArrayConcatenate( const string &StrArray[] )
{
  string Str = "";
  const int Size = ArraySize(StrArray);
  
  for (int i = 0; i < Size; i++)
    Str += StrArray[i];
    
  return(Str);
}

void OnStart()
{
  string StrArray[] = {"abcd", "123", "zxc", "890", "qwert"};
  string Str1, Str2;

// 将所有数组字符串合并为一个字符串 
  Str1 = StringArrayConcatenate(StrArray);
  _W(Str2) = StrArray;
  
  Print(Str1);
  Print(Str2); 
}

突出显示--相同的结果却有巨大的不同

abcd123zxc890qwert
abcd123zxc890qwert
 
更新后,它将可
// 设置自定义结构
struct STRUCT
{
  int i;

  // 设置赋值运算符
  void operator =( const STRUCT& ) {}
};

// 演示通过库函数绕过 _R 结构的自定义赋值操作符的结果
  STRUCT Struct;                         // 使用自定义赋值操作符创建对象
  Struct.i = 1;

  ArrayPrint(_R(Struct).Bytes);          // 确保赋值操作符
  PRINT(_R(Struct) == Struct)            // 不会影响图书馆的 _R 功能

// 检查类型赋值运算符的 "正确性
  PRINT(_WRONG_ASSIGN_OPERATOR(int))     // 正确
  PRINT(_WRONG_ASSIGN_OPERATOR(MqlTick)) // 正确
  PRINT(_WRONG_ASSIGN_OPERATOR(STRUCT))  // 不正确
 
  • Определение корректности оператора присваивания структур.

举例说明该功能如何有助于检测潜在错误。

编写并运行脚本。

#include <TypeToBytes.mqh>

struct STRUCT
{
  int i;
  
  STRUCT() : i(0) {}
  
  template <typename T>
  void operator =( T& ) {}
};

#define  PRINT(A) ::Print(#A + " = " + (string)(A));

void OnStart()
{
  PRINT(_WRONG_ASSIGN_OPERATOR(STRUCT))
}


结果。

_WRONG_ASSIGN_OPERATOR(STRUCT) = true

这表明赋值操作符不会将结构复制到相同类型的结构中。


如果我们向结构体中添加更多内容,结果将是一样的、

  void operator =( STRUCT &Value ) { this.i = 0; }

结果将是一样的。


将该操作符固定为

  void operator =( STRUCT &Value ) { this.i = Value.i; }

似乎就能保证一切顺利,但程序库却不这么认为。


也许,这就是本例中最微妙的地方。

我们将运算符固定为

#include <TypeToBytes.mqh>

struct STRUCT
{
  int i;
  
  STRUCT() : i(0) {}
  
  template <typename T>
  void operator =( T& ) {}

  void operator =( const STRUCT &Value ) { this.i = Value.i; }
};

#define  PRINT(A) ::Print(#A + " = " + (string)(A));

void OnStart()
{
  PRINT(_WRONG_ASSIGN_OPERATOR(STRUCT))
}

得到的结果是

_WRONG_ASSIGN_OPERATOR(STRUCT) = false


现在复制操作符的写法正确了!

你可以用类似的方法检查任何简单结构 的赋值/复制操作符的正确性。

 
NULL 字符串 和空字符串 有什么区别?
#include <TypeToBytes.mqh>

#define  PRINT(A) ::Print(#A + " = " + (string)(A));

void OnStart()
{  
  const string StrNull = NULL;
  
  PRINT(ArraySize(_R(StrNull).Bytes))
  PRINT(ArraySize(_R("").Bytes))
}

结果

ArraySize(_R(StrNull).Bytes) = 0
ArraySize(_R().Bytes) = 1

NULL字符串的长度为零字节。空字符串的长度为 1 字节(0 为字符串的末尾)。