![]() |
|||||||||||||||||||||||||||
|
[wiki系列] openmp/samp 关键字:指令 - 打印版本 +- samp | open.mp 联机社区论坛 (https://open-mp.cn) +-- 板块: SA-MP (https://open-mp.cn/forumdisplay.php?fid=12) +--- 板块: 教程 (https://open-mp.cn/forumdisplay.php?fid=17) +--- 主题: [wiki系列] openmp/samp 关键字:指令 (/showthread.php?tid=23) |
|||||||||||||||||||||||||||
[wiki系列] openmp/samp 关键字:指令 - 小鸟unsigned - 03-21-2026 [wiki系列] openmp/samp 关键字:指令来自 SA-MP Wiki 目录
#assert此指令会检查常量表达式是否为真,如果不为真则停止编译。 代码: #define MOO 10以上代码可以正常编译。 代码: #define MOO 1以上代码无法编译,会产生致命错误。 这类似于: 代码: #define MOO 1但是 #assert 会给出以下错误信息:代码: "Assertation failed: 1 > 5"而第二种写法会给出: 代码: "User error: Moo check failed"哪种错误信息更实用,则视情况而定。 #define#define 是一个文本替换指令。只要在代码中找到被定义的符号(宏名),就会将其替换为定义的内容。代码: #define MOO 7会被替换为: 代码: printf("%d", 7);这也是为什么反编译后的代码中看不到任何 #define,因为所有指令都在预处理器阶段处理完毕。定义的内容不一定是数字:代码: #define PL new i = 0; i < MAX_PLAYERS; i++) if (IsPlayerConnected(i)会编译成大家熟悉(或讨厌)的玩家循环。注意括号的使用:一部分来自 for 语句,一部分来自宏本身。另一个鲜为人知的特性是:定义可以跨行(通过在行尾加上反斜杠 \ 来转义换行)。一般来说换行会结束定义,但下面这样是有效的:代码: #define PL \\ 字符表示定义继续到下一行。#define 的第三个重要特性是支持参数(宏参数)。参数用 %0 到 %9 表示,用法与普通函数参数类似:代码: #define MOO(%0) \输出结果为 42(不是随意选的)。注意宏里多余的括号——这是因为宏是纯文本替换,所以实际编译成: 代码: printf("%d", ((6) * 7));这样是安全的。但看下面这个例子: 代码: printf("%d", MOO(5 + 6));你会期望结果是 77((5 + 6) * 7)。加上括号后确实如此;如果去掉括号: 代码: #define MOO(%0) \实际会变成: 代码: printf("%d", 5 + 6 * 7);由于运算优先级(BODMAS),结果变为 47(5 + (6 * 7)),这就完全错误了。 关于参数还有一个有趣的事实:如果传入的参数数量超过定义的数量,最后一个参数会包含所有多余的部分。例如: 代码: #define PP(%0,%1) \实际会打印: 代码: hi hello hi因为 %1 包含了 "hi", "hello", "hi"。你可能还注意到 # 可以把字面量转换成字符串,这是 openmp(samp) 特有的功能,这里只是为了区分参数。#else#else 相当于普通 else,但用于 #if 条件。#elseif#elseif 相当于 else if,但用于 #if 条件。代码: #define MOO 10#emit此指令在 pawn-lang.pdf 的表格中并未列出,但实际存在。它相当于内联汇编器,如果你熟悉 AMX 字节码,可以用它直接插入 AMX 操作码。唯一限制是每次只能带一个参数。 语法: #emit <opcode> <argument><argument> 可以是小数、整数或(局部/全局)符号(变量、函数、标签)。操作码列表及其含义可在 Pawn Toolkit ver. 3664 中找到。 #endif#endif 相当于 #if 的结束括号。#if 不使用大括号,所有条件内容一直持续到对应的 #endif。#endinput , #endscript此指令停止当前文件的包含(不再继续读取该文件)。 #error此指令立即停止编译,并输出自定义错误信息。示例见 #assert。#if#if 是预处理器版本的 if。你可以精确控制哪些代码被编译、哪些不被编译。例如:代码: #define LIMIT 10会编译成: 代码: if (10 < 10)编译器知道这个条件永远为假,因此会给出“常量表达式”警告。但既然永远不会成立,为什么还要保留这段代码呢?你可以直接删掉,但之后别人修改 LIMIT 重新编译时就无法检查了。这就是 #if 的作用。普通 if 在常量表达式时会警告,而 #if 必须 是常量表达式:代码: #define LIMIT 10这样会在编译时就检查限制是否过小,如果是则直接报错,而不用运行脚本测试。同时也不会生成多余的代码。注意 #if 不强制使用括号(虽然复杂表达式可能需要)。另一个例子: 代码: #define LIMIT 10同样是常量检查,会产生警告,而且两个 printf 都会被编译(尽管我们知道只会执行一个)。用 #if 改写后:代码: #define LIMIT 10这样只有需要的 printf 会被编译,另一个仍保留在源代码中(方便以后改 LIMIT),但不会占用最终编译后的代码空间,也不会每次运行都执行无用的判断。#include此指令会把指定文件的所有代码插入到 #include 所在的位置。有两种包含方式:相对路径(用双引号)和系统路径(用尖括号,我自己起的名称,如果你有更好的叫法请告诉我)。相对包含使用双引号,路径相对于当前文件: 代码: #include "me.pwn"会包含与当前文件同目录下的 me.pwn。系统包含使用尖括号,从 Pawn 编译器所在目录下的 include 文件夹(或其父目录的 include 文件夹)中查找:代码: #include <me>会包含 qawno/include/me.inc(注意没有扩展名;如果文件不是 .p 或 .inc,可以指定扩展名)。两种方式都支持子目录: 代码: #include "folder/me.pwn"如果文件不存在,编译会立即失败。 #pragma说明这是最复杂的指令之一。它提供了一系列选项来控制脚本的编译行为。例如: 代码: #pragma ctrlchar '$'会把转义字符从 \ 改成 $,所以换行符不再是 "\r\n",而是 "$r$n"。很多选项原本是为嵌入式系统设计的,用来限制 PC 上几乎无限制的资源。这里只列出与 openmp(samp) 相关的选项(完整列表见 pawn-lang.pdf)。 列表
示例已弃用(Deprecated)代码: new使用 gOldVariable 时会产生警告,提示不应再使用它。主要用于函数更新 API 时保留向下兼容性。#tryinclude类似于 #include,但如果文件不存在,编译不会失败。这非常适合根据用户是否安装了特定插件(或插件的 include 文件)来选择性包含功能。myinc.inc: 代码: #if defined _MY_INC_INC主脚本: 代码: #tryinclude <myinc>只有当 myinc.inc 存在并被成功包含时,才会调用 MyIncFunc()。这对 IRC 插件等需要检测插件是否安装的情况非常有用。#undef移除之前定义的宏或常量符号。 代码: #define MOO 10第二个 printf 会编译失败,因为 MOO 已被取消定义。代码: enum#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa# 社区交流群: 673335567 论坛: https://open-mp.cn/ |