samp | open.mp 联机社区论坛
[教程] Pawn 中的压缩字符串 原文作者: Emmet_ - 打印版本

+- 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)
+--- 主题: [教程] Pawn 中的压缩字符串 原文作者: Emmet_ (/showthread.php?tid=25)



[教程] Pawn 中的压缩字符串 原文作者: Emmet_ - 小鸟unsigned - 03-21-2026

Pawn 中的压缩字符串



原文作者: Emmet_ 本篇教程仅为翻译搬运

引言



压缩字符串自 SA-MP 和 Pawn 诞生之初就已存在。然而,很多人并不了解压缩字符串以及它能节省多少内存!本教程将教你压缩字符串的基础知识,以及如何正确操作它们。

什么是压缩字符串?



压缩字符串是一种数组,它将数据存储在每个字节中,而不是像普通数组那样存储在每个单元格中。压缩字符串以小端序存储(即低位字节在前),并且只能容纳 0 到 255 的 ASCII 字符,超出这个范围的数值会绕回。

看这段代码:

代码:
new string[5];
string[0] = 'a';
string[1] = 'b';
string[2] = 'c';
string[3] = 'd';
string[4] = '\0';

'a' 存储在单元格 0,'b' 存储在单元格 1,依此类推。一个单元格基本上占用 4 个字节,所以算一下,上面的字符串大约占用 20 个字节,每个字符占用 4 个字节的空间。

然而,使用下面的代码:

代码:
new string[5 char];
string{0} = 'a';
string{1} = 'b';
string{2} = 'c';
string{3} = 'd';
string{4} = '\0';

'a' 存储在字节 0,'b' 存储在字节 1,依此类推。实际上,上面的字符串只占用 8 个字节,仅包含 2 个单元格!

你可能在想为什么这个字符串不是 5 个字节。使用 char 修饰符会自动将数组大小向上取整到最近的 4 的倍数(例如,1 变成 4,3 变成 4,5 变成 8,23 变成 24,依此类推)。

代码:
// 这个数组占用 5 个单元格,共 20 个字节。
new string[5] = "abcd";
// 这个数组占用 2 个单元格,共 8 个字节。
new string[5 char] = !"abcd";

因此,使用压缩字符串可以节省 3 到 4 倍的内存!

适用场景



你可能认为压缩数组没什么用。如果这么想,那你就错了。压缩数组有很多用途,不仅仅是节省内存!

稀疏数组



首先,你可以阅读我关于稀疏数组的教程:

https://sampforum.blast.hk/showthread.php?tid=480439

稀疏数组就是那些大部分数据经常为空的数组。使用压缩数组可以轻松节省内存!

代码:
#define MAX_ITEMS (64)
// 8,192 个单元格 = 32,768 字节!
new gData[MAX_ITEMS][128];
// 2,048 个字节 = 8,192 个单元格!
new gData[MAX_ITEMS][128 char];

不常使用的字符串



很多时候,你会把字符串保存到内存中,但很少使用它们(例如几乎不用)。对于这类数组,压缩数组非常适用。

大量数据存储



回到上面的“稀疏数组”部分,如果你需要存储大量数据,最好使用压缩字符串。

内存节省!



压缩数组能节省 4 倍的内存,既然可以用压缩数组,为什么还要用那些多占 4 倍内存的方式存储数据呢?

SA-MP 中的不支持情况



压缩字符串在纯 Pawn 中完美支持。但是,大多数 SA-MP 原生函数不支持压缩字符串,比如 formatGetPlayerName 等。

如果你打算使用压缩字符串,就必须依赖 strpackstrunpack 以及 string.inc 中的其他字符串函数。

格式化字符串



formatprintf 函数不支持压缩字符串,因此你必须使用 strpack

代码:
new
    string[128 char];
strpack(string, "Hello world!");

你也可以这样做:

代码:
new
    string[128 char],
    temp[128]
;
strpack(string, "Emmet");
strunpack(temp, string);
format(temp, sizeof(temp), "%s likes to eat %s.", temp, "Big Macs");
strpack(string, temp);

支持压缩字符串的函数



string.inc 中的所有字符串函数都同时支持压缩数组和非压缩数组。

freadvalstr 函数也接受一个可选的 pack 参数来支持压缩数组,因此你不用担心它们是否能与压缩数组一起工作。

访问数据



在 Pawn 中,非压缩数组将数据存储在每个单元格中。而压缩数组将数据存储在每个字节中,这意味着你不能像访问非压缩数组那样使用方括号 [] 来访问和获取压缩数组中的数据。

代码:
// 错误。
if (g_PackedString[0] != '\0')
{
    g_PackedString[0] = 'h';
    g_PackedString[1] = 'i';
}
// 正确!
if (g_PackedString{0} != '\0')
{
    g_PackedString{0} = 'h';
    g_PackedString{1} = 'i';
}

另外,要设置一个压缩字符串,你需要在字符串前加上感叹号,以表示这是压缩输入。

代码:
// 错误。这会尝试将字符串按单元格存储,这不是我们想要的!
g_PackedString = "Hello world.";
// 正确!
g_PackedString = !"Hello world.";