从基础到中级:联合(一)·进阶篇
📘

从基础到中级:联合(一)·进阶篇

第 2/2 篇

「用联合体直接改写 64 位字节序」

MQL5 里想在不借助外部库的情况下翻转换行 64 位整型的字节排列,union 是最直接的办法。下面这段代码把 0xA1B2C3D4E5F6789A 放进联合体,再对两个 32 位成员做交换,运行后终端会先打印 Before modification: 0xA1B2C3D4E5F6789A,再打印 After modification : 0x9A78F6E5D4C3B2A1,相当于把大端序翻成了小端序。 如果你在 MT5 里跑这段代码,注意 union 的成员共享同一段内存,修改 u32_bits[0] 会立刻反映到 u64_bits 上。外汇与贵金属行情数据常涉及跨平台字节序差异,这种手法在处理历史 tick 二进制流时可能派上用场,但杠杆交易本身高风险,验证代码别直接挂实盘。 另一种写法是用 uchar 数组覆盖整个 ulong,这样能逐字节操作而不局限于 32 位一组。下面第三段示例开头声明了 un_01,内含 u8_bits[sizeof(ulong)],sizeof(ulong) 在 MT5 里固定为 8,意味着你能精确按字节寻址。

MQL5 / C++
class="type">void OnStart(class="type">void)
{
   union un_01
   {
      class="type">ulong  u64_bits;
      class="type">uint   u32_bits[class="num">2];
   }info;

   class="type">uint tmp;

   info.u64_bits = 0xA1B2C3D4E5F6789A;

   PrintFormat("Before modification: 0x%I64X", info.u64_bits);

   tmp = info.u32_bits[class="num">0];
   info.u32_bits[class="num">0] = info.u32_bits[class="num">1];
   info.u32_bits[class="num">1] = tmp;

   PrintFormat("After modification : 0x%I64X", info.u64_bits);
}

class="type">void OnStart(class="type">void)
{
   union un_01
   {
      class="type">ulong  u64_bits;
      class="type">uchar  u8_bits[class="kw">sizeof(class="type">ulong)];
   };

   un_01 info;

用联合体把 64 位整数按字节翻转

MQL5 里想直接操作一个 ulong 的底层字节,最干净的做法是联合体(union)。下面这段定义了一个 un_01,让 u64_bits 和 u8_bits[8] 共用同一块内存——因为 sizeof(ulong) 在 MT5 里固定是 8 字节,所以数组恰好覆盖整串数据。 初始化写入 0xA1B2C3D4E5F6789A 后,PrintFormat 打出的 'The region is composed of %d bytes' 会显示 8,证明联合体占用就是 8 字节。修改前打印是 0xA1B2C3D4E5F6789A,这是小端机上的原始排列。 翻转逻辑放在独立函数 Swap() 里更利于复用:i 从 0 往上、j 从 sizeof(info)-1 往下,两两交换 u8_bits 直到 i<j 不成立。跑完再打印 u64_bits,值会变成 0x9A78F6E5D4C3B2A1,相当于把整段 64 位做了字节序反转。 外汇与贵金属杠杆高、滑点随机,这类底层内存技巧只建议在指标或 EA 的离线调试中用,实盘前务必在策略测试器跑一遍确认字节序符合预期。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Daniel Jose"
class=class="str">"cmt">//+------------------------------------------------------------------+
union un_01
{
   class="type">ulong u64_bits;
   class="type">uchar u8_bits[class="kw">sizeof(class="type">ulong)];
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart(class="type">void)
{
   un_01 info;

   info.u64_bits = 0xA1B2C3D4E5F6789A;

   PrintFormat("The region is composed of %d bytes", class="kw">sizeof(info));

   PrintFormat("Before modification: 0x%I64X", info.u64_bits);

   Swap(info);

   PrintFormat("After modification : 0x%I64X", info.u64_bits);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void Swap(un_01 &info)
{
   for (class="type">uchar i = class="num">0, j = class="kw">sizeof(info) - class="num">1, tmp; i < j; i++, j--)
   {
      tmp = info.u8_bits[i];
      info.u8_bits[i] = info.u8_bits[j];
      info.u8_bits[j] = tmp;
   }
}
class=class="str">"cmt">//+------------------------------------------------------------------+

◍ 用联合体翻转 64 位字节序

MQL5 里联合体(union)能让同一块内存以不同位宽解读。下面这段演示了把一个 64 位整型赋固定值后,逐字节首尾交换,验证大小端翻转是否生效。 联合体 un_01 同时挂了 u64_bits 和 u8_bits[8],sizeof(info) 在 x64 终端下是 8 字节。初始值 0xA1B2C3D4E5F6789A 写入后,按字节数组看就是 {0xA1,0xB2,0xC3,0xD4,0xE5,0xF6,0x78,0x9A}。 Swap 函数用双指针 i、j 从两端向中间走,把 u8_bits[i] 与 u8_bits[j] 互换。循环条件 i<j 保证只跑 4 次就完成整段反转,不会重复交换。 跑完之后 PrintFormat 打出 Before 与 After:原值 0xA1B2C3D4E5F6789A 会变成 0x9A78F6E5D4C3B2A1。开 MT5 新建脚本粘下面代码,能在专家日志直接核对这组十六进制。外汇与贵金属行情数据跨平台对接时,字节序错乱会导致报价解析异常,这类底层校验在高风险环境下值得手动过一遍。

MQL5 / C++
{
   un_01 info;

   info.u64_bits = 0xA1B2C3D4E5F6789A;

   PrintFormat("The region is composed of %d bytes", class="kw">sizeof(info));

   PrintFormat("Before modification: 0x%I64X", info.u64_bits);

   PrintFormat("After modification : 0x%I64X", Swap(info).u64_bits);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
un_01 Swap(const un_01 &arg)
{
   un_01 info = arg;

   for (class="type">uchar i = class="num">0, j = class="kw">sizeof(info) - class="num">1, tmp; i < j; i++, j--)
   {
      tmp = info.u8_bits[i];
      info.u8_bits[i] = info.u8_bits[j];
      info.u8_bits[j] = tmp;
   }

   class="kw">return info;
}
class=class="str">"cmt">//+------------------------------------------------------------------+

「收束」

这一节把联合(union)在 MQL5 里的初探收了个口:前文跑过的几个实际场景只是地基,更复杂的结构体嵌套与内存复用会在后续篇章展开。附件 ZIP 仅 1.98 KB,里面是本文主要示例的源码,开 MT5 直接丢进 MetaEditor 就能编译验证。 外汇与贵金属属于高风险品种,用联合做底层数据结构优化时,别指望它替你过滤行情风险,该做的仓位控制一步不能省。 下一篇会回到 MQL5 基础语法的深讲,建议从《从基础到中级:变量 (I)》顺着链接往上翻,比直接跳进联合章节更顺。写这套教程的初衷就是让人从零跟到中级,材料偏进阶时回头补前篇即可。

常见问题

用联合体把同一块内存映射为 long 和 uchar[8],直接下标赋值交换即可,无需逐位移位。
只要确认源数据是小端还是大端,对应交换 0-7 和 7-0 下标即可,高风险品种先打印验证再上线。
可以,小布能直接读取你贴的代码并在模拟数据上跑出每字节结果,帮你核对端序是否翻对。
联合体零额外运算、可读性高,且避免移位在部分平台被优化出错,适合高频调用场景。
联合体成员共享内存,改写 uchar 数组会同步改变 long 值,使用时别再当原 long 解读。