#define 宏名
#define 宏名 替换宏名的代码
功能1:定义宏名(宏定义符号),从下一行开始让defined(宏名)返回true(AMXX1.8.3以下版本返回1).这种用法常见于inc文件的顶部.
示例:
#include amxmodx
public plugin_init()
{
register_plugin("测试插件", "1.0.0", "插件作者");
server_print("[AMXX]defined(name) = %d", defined(name));
#define name
server_print("[AMXX]defined(name) = %d", defined(name));
}
进入游戏后,按下 [~] 按键打开控制台,可以看见打印结果:
[AMXX]defined(name) = 0
[AMXX]defined(name) = 1
需要注意,任何"指令"和"运算词"都是在编译时执行的,而函数体内的其它代码是在游戏运行时执行的.
不要以为#define和defined在函数体内就会像new或static一样在游戏运行时执行.
编译时,代码中的所有defined已经被替换为true或false(0或1).而不是在函数运行过程中临时发生变化.
功能2:定义宏名和替换宏名的代码,从指令语句下一行开始,将源码中所有宏名替换掉.
示例:
#include amxmodx
#define dPluginName "测试插件"
#define dPluginVersion "1.0.0"
#define dPluginAuthor "插件作者"
public plugin_init()
{
register_plugin(dPluginName, dPluginVersion, dPluginAuthor);
server_print("[AMXX]插件名称 = %s", dPluginName);
server_print("[AMXX]插件版本 = %s", dPluginVersion);
server_print("[AMXX]插件作者 = %s", dPluginAuthor);
}
进入游戏后,按下 [~] 按键打开控制台,可以看见打印结果:
[AMXX]插件名称 = 测试插件
[AMXX]插件版本 = 1.0.0
[AMXX]插件作者 = 插件作者
高级用法必须了解宏定义指令的书写规则.
首先需要了解标识符命名规则:
在AMXX1.8.3以下版本中,符号名称不得超过31个字节.
在AMXX1.8.2以上版本中,符号名称不得超过63个字节.
符号名区分大小写,比如foo和Foo是两个不同的符号.
名称的第一个字符必须是"_ @ a至z A至Z"这四者之一.
名称的剩余字符必须是"_ @ a至z A至Z 0至9"这五者之一.
宏名不完全受到这些规则限制,但编译器实际只认可符合该规则的部分.
编译器会认为"_@AA我爱你"和"_@AA他爱我"这样的两个宏名是相同的.因为名称左边的"_@AA"符合正常书写规则,而且相同.
接下来了解宏名的书写规则:
宏名的首字符必须是"_ @ a至z A至Z"这四者之一.
宏名总字节数不得超过标识符命名规则所限.
宏名可以含有转义字符.不能含有回车符或换行符.
若宏名含有不符合标识符命名规则的字符.后续内容可用 %0 至 %10 表示外界输入的参数(代码).若有重复参数,则该参数对应最后输入的代码.
若参数被 ( ) 圆括号包裹,参数的后续内容可以是连续的空格或制表符之一.
若名称内含有 ( 左圆括号,右边必须至少有1个 ) 右圆括号.且名称终止位置是最后1个 ) 右圆括号右边的第1个空白字符.
若名称内不含 ( 左圆括号,名称终止位置是右边的第1个空白字符.
然后是了解替换宏名的代码的书写规则:
必须用空白字符将宏名和替换宏名的代码隔开.
内容可以是残缺或完整的语句或表达式,不能是注释.多个语句必须用 , 逗号或 ; 分号相隔.
可以用 %0 至 %10 引用外界输入的代码.编号必须与宏名使用的一致,顺序无限制,使用次数无限制.
若以 \ 反斜杠结尾,下一行也是用于替换宏名的代码.但替换时不会保留换行符.本质上仍然是一行代码.
若后续内容全是空白字符或注释.表示替换宏名的代码已经书写完毕.这些空白字符和注释不会被用于替换宏名.
示例:
#include amxmodx
// ^48和^50是转义字符,对应0和2
#define dCustom((叭叭叭^48Add(^50%3a(%4bcc%1)ttt %3 + %4 + %1
public plugin_init()
{
register_plugin("测试插件", "1.0.0", "插件作者");
server_print("[AMXX]自定义加法(5+6+7) = %d", dCustom((叭叭叭0Add(25a(6bcc7)ttt);
}
进入游戏后,按下 [~] 按键打开控制台,可以看见打印结果:
[AMXX]自定义加法(5+6+7) = 18
这种功能可以用来增加阅读理解成本,使一般人看不懂这段代码.开发者可以用这种方法隐藏类似删库跑路的恶劣代码.
实际上,正常情况下不应该如此极端的使用这种书写规则.
以下是正常的使用方法:
// 格式:符号名称(参数列表) 替换文本
// 将名字太长的函数改更短
#define IsAlive(%0) is_user_alive(%0)
// 以某种格式自动填写某个参数
#define GetWeaponName(%0,%1) get_weaponname(%0, %1, charsmax(%1))
// 将复杂计算改用简短的代码表示
#define GetVectorLength(%0) floatsqroot(%0[0] * %0[0] + %0[1] * %0[1] + %0[2] * %0[2])
在设定了替换宏名代码情况下,拥有 ( ) 圆括号的宏名通常被称呼为宏函数,或函数宏.
而没有 ( ) 圆括号,且替换宏名代码是常量表达式的,通常被称呼为宏常量,或常量宏.