本文节选自本人写作的《 LPC 语言基础教程:从零学习游戏开发》第二章第一节。
第一节 LPC语言基本变量类型
LPC语言的数据类型基本和C语言类似,但是和C语言相同和相似的数据类型只有:整型(int)、浮点型(float)、字符串(string)、数组(array)、结构体(class)。
1. 有符号整型(int)
在C语言中的整数分 short、int、long,还有无符号数 unsigned,但在LPC语言中,只有 int 类型。
在 fluffos 驱动中,int 的长度是8个字节,长度和C语言64 位 Linux 及 Mac OS 下的长整型一样,取值范围是-263 ~ 263-1,即-9223372036854775808~9223372036854775807。
在C语言中,如果数值超出取值范围会超成数据溢出,如下C语言代码,在64位 Linux 系统下,因为溢出,输出结果变成:-9223372036854775808
#include <stdio.h>
int main()
{
long i = 9223372036854775808;
printf("%ld\n", i);
return 0;
}
但是在LPC中,对数据溢出的处理方式不太一样,如果变量赋值超出最大值,取最大值,如果赋值小于最小值,取最小值(截止2019-04-20,fluffos最小值有BUG,实际值为-9223372036854775807),但是对赋值后的变量做运算,会和C语言一样的溢出。
我们修改 test.c
的代码如下:
int main(object me, string arg)
{
// MAX_INT、MIN_INT 为 fluffos 定义宏
int a = MAX_INT, b = MIN_INT;
// 赋值时做运算
int c = MAX_INT + 1, d = MIN_INT - 1, e = d - 1;
// 赋值超出取值范围(10倍)
int f = 92233720368547758070, g = -92233720368547758080;
printf("a = %d\nb = %d\nc = %d\nd = %d\ne = %d\nf = %d\ng = %d\n", a, b, c, d, e, f, g);
}
然后输入指令 test
,输出结果如下:
a = 9223372036854775807
b = -9223372036854775807
c = -9223372036854775808
d = -9223372036854775808
e = 9223372036854775807
f = 9223372036854775807
g = -9223372036854775807
代码中的 MAX_INT
和 MIN_INT
是 fluffos 宏定义的整形最大值和最小值,变量 a、f都取最大值,变量 b、g都取最小值,但从结果看,最小值输出比实际大了1,这是 fluffos 的 BUG。变量 c 运算后溢出,变量 d 理论上应该溢出,但因为系统 BUG ,造成实际取了真实的最小值,变量 e 运行后再次溢出。
注意,如果修改了 test.c
的代码,需要重新编译文件(指令:update /cmds/test)或者重启系统(指令:shutdown)才能生效。
示例代码中的 printf()
函数是LPC语言的 efun,可以理解为类似C语言的库函数(Library Function),因为LPC是从C语言衍生的,语法结构和C语言基本一样,但是C语言的库函数在LPC中不存在,千万不要直接把C语言中的函数在LPMUD开发中直接用,LPC语言中有很多和C语言同名且功能相同或相似的函数,如 printf()
,但也有很多和C语言同名但功能不太一样的函数,如 sizeof()
,还有更多C语言中没有的函数,如 this_player()
,这些独有的函数让LPC开发网络游戏变的更为便捷,关于函数,后续章节会重点介绍。
为方便学习,这里先补充一下格式化输出函数 printf()
的用法,在LPC语言中的用法和C语言中的同名函数基本一样,只是格式控制修饰符和数据类型有一些差异。printf() 格式控制符的完整形式如下:
%[flag][width][.precision]type
[ ] 表示此处的内容可有可无,是可以省略的。
和C语言相比,标志控制符(flag)增加了“|”(列居中对齐)、“=”(字符串纵列模式)、“'X'”(使用指定字符填充空位,X代表任意字符)和 “@”(指明参数为数组);修改了“#”的作用为字符串输出为表格模式。
输出类型(type)只有 "c"、"s"、"d/i"、"f"、"o"、"x/X",作用和C语言一致,同时新增了"O"表示LPC语言数据类型(即可输出LPC语言的任何类型),关于 printf函数 的说明文档可看这里:printf/sprintf。
这里需要特别说明的是,LPC语言中没有字符型(char),但是在输出中可以把整型输出为字符,而且和C语言一样,可以直接把字符赋值给整型变量。C语言中的整数除了可以使用十进制,还可以使用二进制、八进制和十六进制,但是在LPC语言中,整数只能用十进制和十六进制赋值,可以用八进制输出,但不能用八进制赋值,而且即不能用二进制赋值也无法用二进制输出。
修改 test.c
代码如下,并 update /cmds/test
:
int main(object me, string arg)
{
int a = 8, b = 'a', c = 0xF;
printf("a = %o b = %d c = %d\n", a, b, c);
return 1;
}
输出结果为:
a = 10 b = 97 c = 15
如果修改代码使用八进制赋值会发现其实还是十进制,而用二进制赋值的话,代码编译报错。
2. 单精度浮点型(float)
在LPC语言中,小数只有 float 类型,但是实际和C语言中的 double 类型一样,取值范围为 ±1.7E-308 和 ±1.7E308 之间。
和C语言不同的是,LPC语言中的浮点数只能用十进制形式表示,不可以使用指数形式,如果使用指数形式赋值会报错。另外,因为LPC语言中只有一种小数类型,所以,也就没有C语言中的数字加后缀L或F指明类型了。
在 fluffos 中,也定义了二个宏表示特定的浮点数,MAX_FLOAT
表示浮点数的最大值,但是 MIN_FLOAT
却是表示 0.00000,这很奇怪,不知道是 BUG,还是特意这样设定的。另外,在不同的操作系统下,浮点数的最大值和最小值是不一样的。
在 test.c
中使用以下代码试试看,会输出一个大到你数不出来的数字(整数部分309位)。
int main(object me, string arg)
{
float f = MAX_FLOAT;
printf("f = %f\n",f);
return 1;
}
3. 字符串类型string)
和C语言差别比较大的一种数据类型,我们知道,C语言中的字符串类型实际上是字符数组,可以使用以下几种方式赋值:
#include <stdio.h>
int main(int argc, char const *argv[])
{
char str1[] = {"mud.ren"};
char str2[] = "mud.wiki";
char *str = "www.mud.ren";
printf("str1 = %s\nstr2 = %s\nstr = %s\n", str1, str2, str);
return 0;
}
在LPC语言中,没有字符类型,无法使用这种方式赋值字符串,但是单独增加了字符串类型(string),可以直接赋值并使用。
int main(object me, string arg)
{
string s = "www.mud.ren";
printf("s = %s\n",s);
return 1;
}
在LPC语言中,对字符串取子字符串的操作很别致而灵活,使用子字符串操作符,形式是:
str[n1..n2];
正整数代表从左开始,负整数代表从右开始,如果数值超过字符串的长度,视为字符串的长度。如果二个数值相等(str[n1..n1]),则传回字符串的第 n1 个字符。如果二个数值都超过字符串的长度,或者第一个数字所指的位置在第二个数字所指位置之后,会传回空字符串“”。
测试如下代码:
int main(object me, string arg)
{
string s = "www.mud.ren";
printf("s = %s\n",s);
printf("s[4..4] = %s\n",s[4..4]);
printf("s[4..6] = %s\n",s[4..6]);
printf("s[0..20] = %s\n",s[0..20]);
printf("s[20..30] = %s\n",s[20..30]);
printf("s[1..0] = %s\n",s[1..0]);
return 1;
}
输出结果:
s = www.mud.ren
s[4..4] = m
s[4..6] = mud
s[0..20] = www.mud.ren
s[20..30] =
s[1..0] =
4. 数组类型(array)
数组类型,LPC语言和C语言的差别还是比较大的,在C语言中数组定义方式为:
dataType arrayName[length];
并且可以使用指针操作数组。例如:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[] = {1, 2, 3, 4};
int *p = arr;
printf("arr[0] = %d\n", *p);
return 0;
}
而在LPC语言中,数组用 ({}) 表示,并且使用类似指针的方式赋值,另外还有使用 外部函数 allocate()
初始化的方式。具体定义数组的方式如下:
dataType *arrayName;
我们继续测试如下代码:
int main(object me, string arg)
{
string *str = ({"www", "mud", "ren"});
int *arr = allocate(1 + random(9), (: $1 :));
printf("str = %@-4s\n", str);
printf("str[0] = %s, str[1] = %s, str[2] = %s\n", str[0], str[1], str[2]);
printf("arr = %@','-2d\n", arr);
return 1;
}
数组严格上说不是一种数据类型,只是一种数据集合,关于数组的使用,后续章节会详细讲解,这里先了解LPC语言中数组定义的方式。以上代码中第二种定义中使用了 random()
外部函数,所以使用 test 测试时每次输出是随机的。
5. 结构体类型(class)
结构体本质上也不是一种数据类型,而是一种数据集合,在C语言中数组是一组具有相同类型的数据的集合,而结构体用来存放一组不同类型的数据,但是在LPC语言中完全可以使用混合类型数组来实现存放不同类型的数据,或用使用更灵活的映射类型,所以结构体基本没什么大用,这里只做简单的介绍。
在C语言中的结构体类型关键字是 struct,LPC语言中,把关键词改成 class
了,结构体变量的定义方法和C语言有一点不一样的地方是C语言中结构体定义时 }
后面必须有 分号(;),而LPC语言中不需要,另外LPC语言中结构体赋值取值只能使用 ->
。
这里给一个具体的示例:
class example {
string name;
int age;
string *lover;
}
int main(object me, string arg)
{
// 变量
class example instance = new(class example);
// 赋值
instance->age = 24;
instance->name = "Ivy";
instance->lover = ({"Alice", "Vivian", "Jessica"});
// 取值
printf("name : %s,age : %d, lover : %@-7s\n", instance->name, instance->age, instance->lover);
return 1;
}
因为结构体类型在LPC语言中的定义和声明的方法不太一样,所以推荐使用 class
关键字,其实 struct
关键字也可以用,以上代码中 class
改成 struct
也可以,甚至混用也没错。
网友评论