注册 登录 查询

迷你方式显示论坛 RSS订阅此版新信息  
首页 >> 论坛 >> ┈┋MUD 交流区┋┈ >> 梦幻泥潭 >> 查看帖子
 新帖 新投票 讨论区 精华区 上篇 刷新 平板 下篇


 帖子主题: LPC教学手册
 
头衔 小混混

离线

ivy
门派 秋林拾叶
职务 总舵主
人物等级 炉火纯青
江湖威望 +8
江湖阅历 30
门派贡献 1507
实战经验 22561
文章 534
注册 05-01-09 22:36
发表 2007-04-12 17:47:08 人气:626

LPC的函式

4.1 回顾

现在, 你应该了解 LPC 物件由许多处理变数的函式所组成. 函式执行时就处理 变数, 而经由「呼叫」执行这些函式. 在一个档案裡, 函式之间的前后顺序是无关紧要的. 变数在函式裡面被处理, 变数储存在电脑的记忆体中, 而电脑把它们 当作 0 与 1 来处理. 利用定义资料型态这种方法, 这些 0 与 1 被转换成 可使用的输出及输入结果. 字串 (string) 资料型态告诉 driver , 让你看到或你输入的资料应该是许多字元及数字的形式. 整数 (int) 型态的变数对你来说 就是整数值. 状况 (status) 型态对你来说就是 1 或 0. 无 (void) 资料型态 对你或对机器而言都没有值, 并不是用於变数上的资料型态.

4.2 什麼是函式 ?

就像数学函式, LPC 函式获得输入值, 然后传回输出值. 像 Pascal 语言把程序 (procedure) 和函式 (function) 区分开来. 但是 LPC 不这样做, 而知道这种 区分也是有用的. Pascal 称為程序的东西, 在 LPC 就是无传回值 (void) 型 态的函式. 也就是说, 程序或无传回值函式没有传回输出值. Pascal 称為函式 的东西, 就是有传回输出值的. 在 LPC 裡, 最短的正确函式是:

-------

void do_nothing() { }

-----

这个函式不接受输入, 没有任何指令, 也不传回任何值.

要写出正确的 LPC 函式有三个部分:

1) 宣告 (declaration)

2) 定义 (definition)

3) 呼叫 (call)

就像变数一样, 函式也要宣告. 这样一来, 让 driver 知道: 1) 函式输出的资料是什麼型态 2) 有多少个输入的资料以及它们的型态為何. 比较普通的讲法称 这些输入為参数 (parameter).

所以, 宣告一个函式的格式如下:

传回值型态 函式名称 (参数 1, 参数 2, ..., 参数 N);

底下宣告一个 drink_water() 的函式, 它接受一个字串输入, 而输出一个整数:

-----

int drink_water(string str);

-----

str 是输入的变数名称, 会用於函式之中.

函式定义是描述函式实际上如何处理输入值的程式码.

呼叫则是其他函式之中, 呼叫并执行此函式的地方. 对 write_vals() 和 add() 两个函式来说, 你可能会有这些程式码:

-----

/* 首先, 是函式宣告. 它们通常出现在物件码的开头.

*/

void write_vals();

int add(int x, int y);

/* 接著是定义 write_vals() 函式. 我们假设这函式将会在物件以外被呼叫.

*/

void write_vals() {

int x;

/* 现在我们指定 x 為呼叫 add() 的输出值. */

x = add(2, 2);

write(x+"\n");

}

/* 最后, 定义 add() */

int add(int x, int y) {

return (x + y);

}

-----

请记得, 哪一个函式定义在前都没有关係. 这是因為函式并不是由前往后连续执 行的. 函式只有被呼叫时才会执行. 唯一的要求是, 一个函式的宣告必须出现在 函式的定义之前, 而且也必须在任何函式定义呼叫它之前.

4.3 外部函式 (efuns)

也许你已经听过有人提过外部函式. 它们是外部定义的函式. 跟名称一样, 它们 由 mud driver 所定义. 如果你已经撰写 LPC 程式码很久, 你大概已经发现你 听到的一些式子, 像是 this_player(), write(), say(), this_object()... 等等, 看起来很像函式. 这是因為它们是外部函式. 外部函式的价值在於它们比 LPC 函式要快得多, 因為它们早已经以电脑了解的二进位格式存在著.

在前面的 write_vals() 函式裡, 呼叫了两个函式. 第一个是 add() 函式, 是你宣告及定义的函式. 第二个, 则是称做 write() 的外部函式. driver 早就 帮你宣告并定义这个函式. 你只需要呼叫它.

创造外部函式是為了处理普通的、每天都用得到的函式呼叫、处理 internet socket 的输出与输入、其他用 LPC 难以处理的事. 它们是在 game driver 内以 C 写成的, 并与 driver 一起编译在 mud 开始之前, 让它们执行起来快 得多. 但是对你来说, 外部函式呼叫就像对你的函式呼叫一样. 不过, 任何外部 函式还是要知道两件重要的事: 1) 它的传回值是什麼, 2) 它要什麼参数.

外部函式的详细资料, 像是输入参数和传回值, 常常可以在你的 mud 中的 /doc/efun 目录找到. 我没有办法在这裡详细介绍外部函式, 因為每种 driver 的外部函式都不相同. 但是, 你常常可以藉由「man」 或「help」指令 (视 mudlib 而定) 找到详细的资料. 例如指令「man write」会给你 write 外部 函式的详细资料. 如果都不行, 「more /doc/efun/write」也可以.

看过 write 的详细资料之后, 你应该找到 write 是宣告成这样:

-----

void write(string);

-----

这样告诉你, 要正确呼叫 write 不应该期待它有传回值, 而且要传入一个字串型态的参数.

4.4 定义你自己的函式

虽然在档案中, 你的函式次序谁先谁后都没有关係, 但是定义一个函式的程式码 的先后顺序就非常重要. 当一个函式被呼叫时, 函式定义中的程式码按照出现的 先后顺序执行. 先前的 write_vals() 中, 这个指令:

-----

x = add(2, 2);

-----

如果你想看到 write() 使用正确的 x 值, 就必须把它放在 write() 呼叫之前.

当函式要传回一个值时, 由「return」指令之后跟著与函式相同资料型态的值所完成. 在先前的 add() 之中, 指令「return (x+y);」 把 (x+y) 的值传回给 write_vals() 并指定给 x. 在更普通的层次上来说, 「return」停止执行函式 , 并传回程式码执行的结果给呼叫此函式的函式. 另外, 它将跟在它后面任何式子的值传回呼叫的函式. 要停止执行失去控制的无传回值函式, 使用 return; 而后面不用加上任何东西. 请再次记得, 使用「return」传回任何式子的资料型态「必须」与函式本身的资料型态相符合.

4.5 本章总结

定义 LPC 物件的档案是由函式所组成的. 函式依次由三个部分组成:

1) 宣告

2) 定义

3) 呼叫

函式宣告通常出现在档案的最前面, 在任何定义之前. 不过函式只要求在函式定义之前以及任何函式呼叫它之前宣告它.

函式定义可以任何顺序出现在档案裡, 只要它们都放在宣告之后. 另外, 你不可 以再一个函式裡面定义另一个函式.

函式呼叫则出现在其他任何函式中, 任何程式码想执行你的函式的地方. 呼叫也可以出现在自己的函式定义中, 但是这种做法并不建议给新手去做, 因為它很容易变成无穷迴圈.

函式定义依序由底下的部分所组成:

1) 函式传回值型态

2) 函式名称

3) 一个左小括号 ( 接著列出参数再加上一个右小括号 )

4) 一个左大括号 { 指示 driver 从这裡开始执行

5) 宣告只用在这个函式中的任何变数

6) 指令、式子、视需要呼叫其他函式

7) 一个右大括号 } 描述函式码在此结束. 对於无传回值函式来说, 如果 在此还没有碰到「return」指令 (只适用於无传回值函式) , 会如同有 碰到「return」指令一样回到原来呼叫的函式执行.

最短的函式是:

-----

void do_nothing() {}

-----

因為这个函式不接受任何输入, 不做任何事, 也不传回任何输出.

任何无传回值型态以外的函式「必须」传回一个与函式资料型态相同的值.

每一种 driver 都有一套早已经帮你定义好的函式, 它们叫做外部函式. 你不需 要宣告或定义它们, 因為它们早已经帮你做好这些事. 更深入一点, 执行这些函 式比起执行你的函式要快得多, 因為外部函式是 driver 的一部份. 再者, 每一 个 mudlib 都有特殊函式像是外部函式一样, 早已经為你宣告并定义好. 但是不 同的是, 它们用 LPC 定义在 mudlib 裡面. 它们叫做模拟外部函式 (simul_efuns, 或 simulated efuns). 在大多数的 mud 裡, 你可以在 /doc/efun 目录底下找到关於它们的详细资料. 另外, 很多 mud 有称作 「man 」或「help」的命令, 让你可以方便地叫出这些资料档案.

程式风格的註解:

有些 driver 可能不会要求你宣告函式, 有些不会要求你指定函式的传回值型态. 无论如何, 底下有两个理由劝你不要省略以上这些动作:

1) 对其他人来说 (还有你自己过了一段时间之后) , 会比较容易读懂你的 程式码并了解程式码的意义. 这对除错时特别有用, 有很多错误 (除了放错地方的各种括号) 发生在资料型态上 (有没有碰过「Bad arg 1 to foo() line 32」? (程式第三十二行, 呼叫 foo() 时的第二个参数有错) ).

2) 大家认為这样子写程式是个好习惯.


点击这里给我发消息
相关帖子
LPC教学手册 (ivy,5457,2007-04-12 17:41:06)
    LPC基本简介 (ivy,869,2007-04-12 17:43:36)
    LPC的资料型态 (ivy,538,2007-04-12 17:45:51)
    LPC的函式 (ivy,626,2007-04-12 17:47:08)
    LPC的基础继承 (ivy,454,2007-04-12 17:48:56)
    LPC的变数处理 (ivy,382,2007-04-12 17:49:51)
    LPC的流程控制 (ivy,482,2007-04-12 17:52:24)
    LPC的物件资料型态 (ivy,586,2007-04-12 17:53:16)
    好复杂啊。。。。 (gfdsa1,361,2007-05-20 04:00:57)