AMXXPawn 运算符

目录

1. 简介

运算符(Operator)是能够利用操作数得出数值的符号,是复合表达式的重要组成部分。

部分运算符的操作数类型、计算结果是可以自定义的。点击查看:运算符重载指南

float.inc文件专门为拥有Float标签的操作数重新定义了运算符计算方式,其它类型的操作数都默认执行整数计算。

版本注意:AMXX1.8.3以下和AMXX1.8.2以上版本,浮点数的相关计算结果略有不同,而且某些运算符被禁用。感兴趣的可以自行查阅float.inc文件。

学习建议:以下内容中,看不懂的可以先跳过,需要用到时再翻回来看。还有就是二进制位操作属于常用的必学内容。

操作数表示法

操作数通常是字面量、常量、变量、函数等表达式,还可以是由它们与运算符组合成的表达式。接下来用单个字符表示:

e	   // 任意表达式
v	   // 变量(不能有只读特性,不能是数组)
a	   // 数组(包括数组字面量,字符串字面量)
f	   // 函数
s	   // 任何标识符

仅以下运算符可以对数组进行操作:

= [] {} : ?: , sizeof defined tagof

需要注意,标识符和数值不是一回事,标识符可以当做数值使用,但数值不能当做标识符使用。

运算符的操作结果可能会得到标识符本身,或得到标识符绑定的数值。

2. 算术运算符

运算符 名称 用法 描述
+ 加法运算符 e1 + e2 得到e1加e2的结果
- 求负数
减法运算符
-e
e1 - e2
求e的负数
得到e1减e2的结果
* 乘法运算符 e1 * e2 得到e1乘以e2的结果
/ 除法运算符 e1 / e2 得到e1除以e2的商数,向下取整
% 取模运算符 e1 % e2 模 = e2 - 商 * e1 (商=e1/e2,向负无穷取整)
++ 递增运算符 v++
++v
让v的值增加1
后置++得到旧值
前置++得到新值
-- 递减运算符 v--
--v
让v的值减少1
后置--得到旧值
前置--得到新值

注意:AMXX中并没有定义求正运算符,因此不能用+得到e的正数。

3. 二进制位操作运算符

重要:二进制位操作是AMXXPawn编程中的核心技能,在游戏中应用广泛,务必掌握。

AMXXPawn的所有数值都可用32个位上的0或1表示,左边是高位,右边是低位。

其中,从右往左第32个位称为'符号位',若为0表示数值是正数,若为1表示数值是负数。

源码中可以用0b开头,编写二进制数值字面量(可在数值内任何顺眼的位置穿插下划线),左侧连续的0可以不写。

例如:0b_00001111和0b_1111是同一个数值。

数值的二进制表示:

0000_0000_0000_0000_1111_1111_1111_1111
↑符号位
运算符 名称 用法 描述
~ 按位取反 ~e 得到e在二进制位中的补数,所有位取反,0变1,1变0
>> 有符号右移 e1 >> e2 右移e2位,用符号位相同值填充左侧,右侧溢出位舍弃
>>> 无符号右移 e1 >>> e2 右移e2位,用0填充左侧,右侧溢出位舍弃
<< 左移 e1 << e2 左移e2位,左侧溢出位舍弃,用0填充右侧
& 位与 e1 & e2 保留e1与e2同位上的1,其它全为0。得到交集
| 位或 e1 | e2 保留e1或e2所有位上的1,其它全为0。得到并集
^ 位异或 e1 ^ e2 保留e1和e2不同位上的1,其它全为0。得到对称差集

二进制位操作示例:

~e计算结果
0000_0000_0000_0000_1111_1111_1111_1111 // e的值
1111_1111_1111_1111_0000_0000_0000_0000 // 结果

e1 >> e2 计算结果(假设e2等于4,右移4位)
1000_0000_0000_0000_1111_1111_1111_0000 // e1的值
1111_1000_0000_0000_0000_1111_1111_1111 // 结果

e1 >>> e2 计算结果(假设e2等于4,右移4位)
0100_0000_0000_0000_1111_1111_1111_0000 // e1的值
0000_0100_0000_0000_0000_1111_1111_1111 // 结果

e1 & e2 计算结果,同位上等于1的部分设为1
0000_0000_0000_0000_1111_0000_0000_0000 // e1的值
0000_0000_0000_0011_1100_0000_0000_0000 // e2的值
0000_0000_0000_0000_1100_0000_0000_0000 // 结果

e1 | e2 计算结果,有1的部分设为1
0000_0000_0000_0000_1111_0000_0000_0000 // e1的值
0000_0000_0000_0011_1100_0000_0000_0000 // e2的值
0000_0000_0000_0011_1111_0000_0000_0000 // 结果

e1 ^ e2 计算结果,有差异的位设为1
0000_0000_0000_0000_1111_0000_0000_0000 // e1的值
0000_0000_0000_0011_1100_0000_0000_0000 // e2的值
0000_0000_0000_0011_0011_0000_0000_0000 // 结果

4. 赋值运算符

运算符 名称 用法 描述
= 赋值 v = e 将e的每个数值复制给v
若e非数组,结果为e
若e是数组,维度必须与v相同,e和v的每个多维数组尺寸必须相同,
e的每个1维数组尺寸必须小于等于v内部对应的1维数组尺寸,计算结果是e的地址
+= 加法赋值 v += e v = v + e的简写
-= 减法赋值 v -= e v = v - e的简写
*= 乘法赋值 v *= e v = v * e的简写
/= 除法赋值 v /= e v = v / e的简写
%= 求模赋值 v %= e v = v % e的简写
>>= 右移赋值 v >>= e v = v >> e的简写
>>>= 无符号右移赋值 v >>>= e v = v >>> e的简写
<<= 左移赋值 v <<= e v = v << e的简写
&= 位与赋值 v &= e v = v & e的简写
|= 位或赋值 v |= e v = v | e的简写
^= 位异或赋值 v ^= e v = v ^ e的简写

5. 关系运算符

下列运算符的计算结果皆为0或1,是用于表示真假,是非,对错的数值。

若数值为0,对应常量false,表示否定。若数值非0,对应常量true,表示肯定。

注意:虽然任何非0数都可以表示true,但它的实际数值为1。

运算符 名称 用法 描述
== 等号 e1 == e2 相等得1,反之得0
!= 不等号 e1 != e2 相等得0,反之得1
< 小于 e1 < e2 e1小于e2得1,否则得0
<= 小于等于 e1 <= e2 e1小于等于e2得1,否则得0
> 大于 e1 > e2 e1大于e2得1,否则得0
>= 大于等于 e1 >= e2 e1大于等于e2得1,否则得0

6. 逻辑运算符

下列运算符的计算结果皆为0或1,是用于表示真假,是非,对错的数值。

若数值为0,对应常量false,表示否定。若数值非0,对应常量true,表示肯定。

注意:虽然任何非0数都可以表示true,但它的实际数值为1。

运算符 名称 用法 描述
! 逻辑非 !e 是非颠倒。e为0得1,否则得0
&& 逻辑与 e1 && e2 全都要。两者皆非0,则得1,否则得0
|| 逻辑或 e1 || e2 不可无。两者皆为0,则得0,否则得1

短路求值:假设e2内部含有运算符,&&运算符仅在e1为true时计算e2;||运算符仅在e1为false时计算e2。

7. 其他运算符

运算符 名称 用法 描述
[] 单元索引器 a[e] 访问数组元素,a必须是数组而不是数组字面量
{} 字节索引器 a{e} 访问数组字节(大端序),a必须是数组而不是数组字面量
() 分组运算
调用函数
(e)
f(e1, e2, ...)
若e是多个表达式组成,优先计算e的值,再参与外界运算
以某种顺序对e1,e2,...求值,调用f函数,得到f的返回值
? : 三元运算 e1 ? e2 : e3 若e1非0,则得e2,否则得e3
: 类标签生成与覆盖 s:e 若s不存在则创建值类型标签,否则覆盖e的标签
虽然这其实不是运算符,但解析器源码中是这么称呼它的
点击查看值类型标签指南
: 跳转标签生成 s: 在函数体内生成一个跳转标签,可用goto关键字跳转至标签位置
虽然这其实不是运算符,但解析器源码中是这么称呼它的
点击查看跳转标签指南
, 逗号 e1, e2 得到e2的值
注意:某些逗号是分隔符,而不是运算符
defined 已定义 defined s 检查标识符是否已经定义
sizeof 求尺寸 sizeof s s只能是变量
若s是单值变量,得1
若s是数组变量,得元素数量
tagof 取值类型标签 tagof s s不能是自动机或状态名称
1.8.3以下版本中s不能是值类型标签
取得s的值类型标签uid
char 压缩尺寸 e char 得到(e + 3) / 4的结果
表示储存e个字节最少需要多少个cell
1个cell可以储存4个字节

数组和字节操作示例:

new a[] = { 41, 42, 43, 0 };
new value = a[0];	// 取0号元素值,得到41
a[0] = 40;		// 对0号元素赋值

new b[1] = { 0b_11100110_10001000_10010001_00000000 };
new byteVal = b{0};	// 得到0b_11100110
byteVal = b{1};		// 得到0b_10001000
b{2} = 0b_00000000;	// 将10010001部分改为00000000

调用函数注意事项:若未填写参数、或编译器含有-(+选项,不可省略()运算符。反之可省略。

点击查看函数与参数指南

8. 优先级

运算符优先级决定将某些表达式视作一组,优先求值。

代码示例:

v = e1 + e2 * e3	// 分组结果:(v = (e1 + (e2 * e3))),最内层括号优先求值
v = (e1 + e2) * e3	// 使用圆括号改变分组结果:(v = ((e1 + e2) * e3))

运算符优先级从高到低(1级最高,15级最低):

级别 运算符
1 () [] {}
2 ! ~ -(负号) ++ -- : char defined sizeof tagof
3 * / %
4 + -(减号)
5 >> >>> <<
6 &
7 ^
8 |
9 < <= > >=
10 == !=
11 &&
12 ||
13 ? :
14 = *= /= %= += -= >>= >>>= <<= &= ^= |=
15 ,