整数
整数类型用于存储不带小数点的数字。如果值的应用意义与分数无关,就应选用整数类型。例如,图表上的条数或未平仓头寸数始终是整数。
在 MQL5 中, 可以使用 char、short、int、long 等关键字,选择大小为 1 至 8 个字节的整数类型。整数均为有符号类型,即可以是正值和负值。如有必要,可以将相同大小的整数类型声明为无符号类型(名称都以 'u’ 开头,表示“无符号”):uchar、ushort、uint、ulong。
下表根据类型大小以及有符号还是无符号显示了可能值的范围。
类型 |
最小值 |
最大值 |
---|---|---|
char |
-128 |
127 |
uchar |
0 |
255 |
short |
-32768 |
32767 |
ushort |
0 |
65535 |
int |
-2147483648 |
2147483647 |
uint |
0 |
4294967295 |
long |
-9223372036854775808 |
9223372036854775807 |
ulong |
0 |
18446744073709551615 |
我们没有必要记住上述每种整数类型的极限值。MQL5 中有许多预定义的命名常量,可在代码中用于替代魔术数字(包括最小/最大整数)。这种技术将在涉及 预处理器的相关章节中讨论。这里,我们只列出相关的命名常量:CHAR_MIN、CHAR_MAX、UCHAR_MAX、SHORT_MIN、SHORT_MAX、USHORT_MAX、INT_MIN、INT_MAX、UINT_MAX、LONG_MIN、LONG_MAX 和 ULONG_MAX。
我们说明一下获得这些值的方法。为此我们需要回顾一下位和字节的概念。
一个字节包含 8 个位,每个位有“启用”和“禁用”这两种状态,所有可能组合数量为 256。因此,一个字节中可以存储的值的范围是 0 至 255。但是,对它们的编译取决于为此字节分配的类型。编译器会根据程序员的语句,确保不同编译方式都能实现。
一个字节中的低阶(最右边)位为 1,第二位为 2,第三位为 4,以此类推,直到高阶位 128。显而易见,这些数字等于二的位数次方的幂(从 0 开始计数)。以下是二进制的图解。
位 |
高阶 |
低阶 |
||||||
---|---|---|---|---|---|---|---|---|
数字 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
值 |
128 |
64 |
32 |
16 |
8 |
4 |
2 |
1 |
当所有位都被置位(设置为 1)时,得到二的所有幂次之和,即 255,这是一个字节的最大值。如果所有位都被重置(设置为 0),我们得到零。如果低阶位启用(设置为 1),这个数字是一个奇数。
在编码有符号数时,高阶位用于标记负值。因此,对于正数值范围内的单字节整数,最大值是 127。对于负数值,则有 128 种可能的组合,即最小值是 -128。当一个字节的所有位都被置位(设置为 1)时,编译器将其解释为 -1。如果在这样的数字中将低阶位重置(设置为 0),我们得到 -2,以此类推。如果只有高阶位(符号位)被置位(设置为 1),其他所有位为 0,我们得到 -128。
这种看似不合理的编码叫做“补码”。这样便可以在硬件层实现有符号和无符号数的统一计算。此外,补码还可以防止值丢失,在正负区域进行相同编码时,通常会发生值丢失的情况:此时我们将得到两个表示零的值,即正 0 和负 0 。而这会带来歧义。
如果数字有多个字节(如 2、4 或 8 个),所有位连续进行编号,各自的值有规律变化。在所有情况下,判定数字为负数的条件是高阶字节的高阶位被置位(设置为 1)。
因此,我们可以使用一个字节来存储一个 0 至 255 范围内的无符号整数(uchar,即无符号字符的缩写)。我们也可以将一个有符号整数写入字节(为此,我们将把它的类型描述为 char)。在这种情况下,编译器会将 256 个组合的可用数在正负值之间平均分配,并将其显示在 -128 至 127 的区域中(第 256 个值为零)。显而易见,将在有符号和无符号字节的位级对值 0 至 127 进行相同编码。然而,大的绝对值(从 128 开始)将转换为负数(根据上文插入部分描述的方案)。这种“转换”仅在读取或执行与存储值相关的操作时才会发生,此时数据内部表示形式(位状态)不变。
我们将在涉及 类型强制转换的相关章节中更深入讨论这个问题。
与单字节整数类似,很容易计算出 2 个字节的位组合数为 65536。因此,这类范围是针对有符号和无符号双字节整数 short 和 ushort 形成的。其他类型由于字节大小增加,因此可以存储更大的值。
请注意,使用相同大小的无符号类型可以将正值范围加倍。存储可能非常大的数量时(此时不会出现负值),则有必要进行这种操作。例如,MetaTrader 5 中的订单号是 ulong 类型的值。
我们已经在 第一章中遇到过整数说明示例。特别是,uint 类型的输入参数 GreetingHour 也在此处定义:
input uint GreetingHour = 0; |
除了附加的 input 关键字(使变量在 MQL 程序的参数列表中可见),其他组成部分(包括类型、名称和 '=' 符号后的可选初始化)是所有变量固有的属性。
我们将在 变量 一节中详细讨论变量说明语法。至此,请注意表示整型常量的方法。在描述变量时,常量可以被指定为默认值(在上面的例子中,是 0)。此外,常量可以用于 表达式中,例如,用于公式事件中。
需注意,插入源代码中的任何类型的常量被称为字面量(字面意思:“逐字照搬”)。之所以称为字面量是因为它们“按原样”被引入程序中,并且在说明的位置立即使用。字面量与语言的其他元素(尤其是变量)有很大区别,字面量既没有名称,也不能从程序的其他位置引用。
对于负数,数字前必须有负号 '-';而对于正数,则可以省略正号 '+',即 +100 和 100 格式没有区别。
应该注意的是,数字值通常按我们惯用的十进制记数法记录在源代码中。但是,MQL5 允许使用另一种计数法,即十六进制计数法。这种方法对于处理位级信息(参见 按位运算)非常方便。
十进制常量的所有数位都允许使用从 0 到 9 的数字,而对于十六进制常量,除了数字之外,还会额外使用字符 A 到 F 或 a 到 f(即不区分大小写)。“十六进制数字”A 对应于十进制记数法的数字 10,B 对应 11,C 对应 12,以此类推,直至 F 对应 15。
十六进制常量的一个显著特征是它以前缀 0x 或 0X 开头,后面跟数字的有效数位。例如,在十六进制系统中,数字 1 表示为 0x1,而 16 表示为 0x10(因为 16 大于 15,即 0xF,所以需要一个额外的高位)。十进制的 255 转为十六机制就是 0xFF。
让我们再举一些例子来说明使用整数类型描述变量的各种情况(附在 MQL5/Scripts/MQL5Book/p2/TypeInt.mq5 脚本中):
void OnStart()
|
x 变量由允许的负值 -10 正确初始化。
y 变量无符号。因此,尝试表示一个负值,我们会得到一个有趣的结果。数字 -1 采用位表示形式,程序会根据无符号类型 uint 来解释。这样得到数字 4294967295(它实际上等于 UINT_MAX)。
z 变量被赋予浮点数值 1.23(将在下一节讨论相关内容),这时编译器警告小数部分被截断。结果是,整数 1 存入变量中。
h 变量由十六进制形式的常量 (0x1000 = 4096) 成功初始化。
大数值 10000000000 记录在 p 和 w 变量中,前者是一个长整数类型 (long) 且成功处理,而后者是一个普通类型 (int),因此引发了编译器警告。由于该常量超过了 int 的最大值,因此编译器会截断多余的高阶数字(位),这导致 1410065408 存入 w。
这一行为在类型转换开发过程中可能造成的潜在负面问题之一,而程序员不一定会表明这一点。在后面的例子中,就存在一个潜在错误。很明显,在这个特殊的例子中,故意选择了错误的值来演示警告。而在实际的程序中,我们不一定一眼就能看出程序会将哪些值存入整数变量。因此,您应该非常仔细地查看编译器警告,并更改类型或明确指定所需的类型强制转换,以尝试消除这些警告。这将在涉及 类型强制转换的相关章节中讨论这一问题。
对于整数类型,定义了算术运算、位运算和其他类型的运算(参见 表达式一章)。