LPC 语言基础教程:2.3 LPC语言的变量和常量

本文节选自《LPC语言基础教程:从零学习游戏开发》,版权归@mudren,欢迎转载,但必须注明来源(mud.ren)。

第三节 LPC语言变量和常量

数据有类型,也有常量和变量之分,下面我们具体介绍。

变量

变量(varible)可以理解成一块内存区域的名字。通过变量名,可以引用这块内存区域,获取里面存储的值。由于值可能发生变化,所以称为变量,否则就是常量了。

在LPC语言中变量的定义和初始化方式和C语言完全相同:

数据类型符 变量名1[,变量名2,...];
数据类型符 变量名1=初值1[,变量名2=初值2,...];

和C语言一样,LPC语言中的局部变量定义必须在可执行语句或代码块的开头。不像其它高级语言可以在哪儿使用在哪儿声明。

下面详细介绍变量相关知识,这些LPC语言和C语言差别不大,这里重点关注和C语言的不同点。

变量名

变量名在 C 语言里面属于标识符(identifier),命名有严格的规范。

  • 只能由字母(包括大写和小写)、数字和下划线(_)组成。
  • 不能以数字开头。
  • 长度不能超过63个字符。

下面是一些无效变量名的例子。

$zj
j**p
2cat
Hot-tab
tax rate
don't

上面示例中,每一行的变量名都是无效的。

变量名区分大小写,starStarSTAR都是不同的变量。

并非所有的词都能用作变量名,有些词在 C 语言里面有特殊含义(比如int),另一些词是命令(比如continue),它们都称为关键字,不能用作变量名。另外,C 语言还保留了一些词,供未来使用,这些保留字也不能用作变量名。

在C语言中一共有32个关键字,LPC语言中的关键字和C语言有一些差别,LPC语言中的关键字具体如下(以fluffos为标准):

LPC语言关键字 说明 备注
__TREE__ #ifdef DEBUG
array 声明数组变量或函数 #ifdef ARRAY_RESERVED_WORD
asm
break 跳出当前循环
buffer 声明缓冲类型变量或函数
case 开关语句分支
catch
class 声明结构体变量或函数 #ifdef STRUCT_CLASS
closure #ifdef COMPAT_32
continue 结束当前循环,开始下一轮循环
default 开关语句中的“其他”分支
do 循环语句的循环体(与 while 连用)
efun 调用外部函数
else 条件语句否定分支(与 if 连用)
float 声明浮点型变量或函数
for 一种循环语句
foreach 一种循环语句
function 声明函数指针类型变量
if 条件语句
in 用于 foreach 循环语句
inherit 继承对象的方法
int 声明整型变量或函数
mapping 声明映射类型变量或函数
mixed 声明混合类型变量或函数
new
nomask 声明方法类型为不可被重写的(类似其它面向对象语言中的final)
nosave 声明变量类型为nosave #ifdef SENSIBLE_MODIFIERS
object 声明对象类型变量或函数
parse_command
private 声明方法类型为私有
protected 声明方法类型为被保护的
public 声明方法类型为公开的(默认类型)
ref #ifdef REF_RESERVED_WORD
return 子程序返回语句(可以带参数,也可不带参数)循环条件
sscanf
static 声明静态变量 #ifndef SENSIBLE_MODIFIERS
string 声明字符串变量或函数
struct 声明结构体变量或函数 #ifdef STRUCT_STRUCT
switch 用于开关语句
time_expression
varargs 声明函数参数为可变长度
void 声明函数无返回值或无参数
while 循环语句的循环条件

关键字是不可以做变量和函数名的,因为LPC和C的关键字的不同,定义变量和函数时要注意了。

另外,驱动预定义的常量不可以做变量名,如:__DIR__(表示当前目录)、__FILE__(表示当前文件)、__LINE__(表示当前行)、__VERSION__(当前驱动版本)等等。

变量的声明

C 语言的变量,必须先声明后使用。如果一个变量没有声明,就直接使用,会报错。

每个变量都有自己的类型(type)。声明变量时,必须把变量的类型告诉编译器。

int height;

上面代码声明了变量height,并且指定类型为int(整数)。

如果几个变量具有相同类型,可以在同一行声明。

int height, width;

// 等同于
int height;
int width;

注意,声明变量的语句必须以分号结尾。

一旦声明,变量的类型就不能在运行时修改。

变量的赋值

C 语言会在变量声明时,就为它分配内存空间,但是不会清除内存里面原来的值。这导致声明变量以后,变量会是一个随机的值。所以,变量一定要赋值以后才能使用。

赋值操作通过赋值运算符(=)完成。

int num;
num = 42;

上面示例中,第一行声明了一个整数变量num,第二行给这个变量赋值。

变量的值应该与类型一致,不应该赋予不是同一个类型的值,比如num的类型是整数,就不应该赋值为小数。虽然 C 语言会自动转换类型,但是应该避免赋值运算符两侧的类型不一致。

变量的声明和赋值,也可以写在一行。

int num = 42;

多个相同类型变量的赋值,可以写在同一行。

int x = 1, y = 2;

注意,赋值表达式有返回值,等于等号右边的值。

int x, y;

x = 1;
y = (x = 2 * x);

上面代码中,变量y的值就是赋值表达式(x = 2 * x)的返回值2

由于赋值表达式有返回值,所以 C 语言可以写出多重赋值表达式。

int x, y, z, m, n;

x = y = z = m = n = 3;

上面的代码是合法代码,一次为多个变量赋值。赋值运算符是从右到左执行,所以先为n赋值,然后依次为mzyx赋值。

C 语言有左值(left value)和右值(right value)的概念。左值是可以放在赋值运算符左边的值,一般是变量;右值是可以放在赋值运算符右边的值,一般是一个具体的值。这是为了强调有些值不能放在赋值运算符的左边,比如x = 1是合法的表达式,但是1 = x就会报错。

LPC语言中的不同点

在C语言中整型变量分有符号型、无符号型、基本整型、短整型、长整型,但LPC中只有基本整型变量。

在C语言中可以使用 const 关键字定义有名常量,但LPC语言中,没有这种用法,也没有 const 关键字。

另外,在C语言中有取地址指针运算符 & 获取变量的地址,在LPC中没有,LPC游戏开发不需要和底层互交,没有相关功能。

这里强调一点,LPC语言中任何变量类型如果只定义没有赋初值,默认初值都是0,而且对这种没有初始化的变量做类型判断时返回的都是 int 类型。

变量的作用域

作用域(scope)指的是变量生效的范围。C 语言的变量作用域主要有两种:文件作用域(file scope)和块作用域(block scope)。

文件作用域(file scope)指的是,在源码文件顶层声明的变量,从声明的位置到文件结束都有效。

int x = 1;

int main(void) {
  printf("%i\n", x);
}

上面示例中,变量x是在文件顶层声明的,从声明位置开始的整个当前文件都是它的作用域,可以在这个范围的任何地方读取这个变量,比如函数main()内部就可以读取这个变量。这种变量被称为全局变量。

块作用域(block scope)指的是由大括号({})组成的代码块,它形成一个单独的作用域。凡是在块作用域里面声明的变量,只在当前代码块有效,代码块外部不可见。这种变量被称为局部变量。

int a = 12;

if (a == 12) {
  int b = 99;
  printf("%d %d\n", a, b);  // 12 99
}

printf("%d\n", a);  // 12
printf("%d\n", b);  // 出错

上面例子中,变量b是在if代码块里面声明的,所以对于大括号外面的代码,这个变量是不存在的。

代码块可以嵌套,即代码块内部还有代码块,这时就形成了多层的块作用域。它的规则是:内层代码块可以使用外层声明的变量,但外层不可以使用内层声明的变量。如果内层的变量与外层同名,那么会在当前作用域覆盖外层变量。

{
  int i = 10;

  {
    int i = 20;
    printf("%d\n", i);  // 20
  }

  printf("%d\n", i);  // 10
}

上面示例中,内层和外层都有一个变量i,每个作用域都会优先使用当前作用域声明的i在LPC语言中作用域内的局部变量不可以重复声明,这是和C语言不同的。

最常见的块作用域就是函数,函数内部声明的变量,对于函数外部是不可见的。for循环也是一个块作用域,循环变量只对循环体内部可见,外部是不可见的。

for (int i = 0; i < 10; i++)
  printf("%d\n", i);

printf("%d\n", i); // 出错

上面示例中,for循环省略了大括号,但依然是一个块作用域,在外部读取循环变量i,编译器就会报错。

LPC语言中局部变量除了不能重复声明外,作用域和C语言完全一至。而全局变量的用法在LPC中比较特别,除了作用域的变化外还有存档相关,具体在后续章节会介绍。

常量

在C语言中整型常量有八进制、十进制、十六进制三种书写形式,而且可以赋值给整型变量。但是LPC中,无法用八进制赋值,具体在第二章第一节的示例 2.1.2.c 中有演示,本人怀疑是LPC的BUG,反正大家别用八进制赋值就对了。另外LPC中整型常量不像C语言中分基本整型、短整型和长整型,只用一种基本整型,取值范围为-263 ~ 263-1。

在C语言中实型(即浮点型)常量有二种书写形式,但在LPC语言中只有十进制小数一种书写形式,取值范围为 ±1.7E-308 和 ±1.7E308 之间。

在C语言中有字符类型变量和常量,但在LPC语言中,只有字符常量,没有字符变量。

在C语言中没有字符串变量,只有字符串常量,但在LPC语言中,既有字符串常量,也有字符串变量。

在LPC语言中的符号常量的用法和C语言一样,使用以下方式定义:

#define 符号常量 常量

在LPC中,驱动预定义了很多常量,具体会在后续第七章宏定义中讲解。

京ICP备13031296号-4