预处理指令字
 [首页][前页]

LPC 预处理区 (preprocessor) 手册
(93.07.17 更新)


  对 LPC 编译器 (compiler) 而言, 预处理区是源代码的最前端, 它提供以下便利的特性:
  共享的定义和源代码 (#include) 
  宏 (macros) (#define, #undef) 
  编译条件 (#if, #ifdef, #ifndef, #else, #elif, #endif) 
  除错 (#echo) 
  使用特定的编译器功能 (#pragma) 
  快速的文章格式 (@, @@) 
  前三个与 C 相同. 如果您熟悉 C 语言, 大概只会浏览此份文件的最后几段文字.

  说明:

  前面以 # 开头的命令 (像是 #include), 其 # 符号必须摆在每行的第一个字, 前面不可留有空白.



共享的定义和源代码


  #include 提供此功能.
语法 1 : #include 
语法 2 : #include "file.h"
  说明:

  语法 1 的形式, 会在系统的标准引用 (include) 目录中, 寻找 file.h. (在 TMI 中是 /include)

  语法 2 的形式, 会在程序文件所在的同一个目录中, 寻找欲引用的 file.h

  #include 语句是以文字命令的方式, 在一个文件中引用另一个文件. 在一个文件中放上像 #include "file.h" 的语句, 就如同 file.h 的内容直接放入 #include 所在的位置. 在每次物件重新编译时, 物件所引用的文件也会重新编译一次. 如果引用的文件里面有变量或函数与此文件中的相同, 编译此文件时会产生双重命名的错误 (duplicate-name error) (如果您把 file.h 的内容放在 #include 的位置, 一样会产生错误).





  宏定义将后面源代码中的一些字换成定义的内容. 目的在于隐藏程序内部的细节、减少打字的数量、便于更改常数 (constant).
语法 1 : #define identifier token_sequence
语法 2 : #define identifier(id_list) token_sequence
  说明:

  惯例上, 源代码中的 identifier 使用大写英文字母以强调它们所出现的位置, 并且在源代码开端或是所引用的表头档 (header file) 中定义其内容.

  第二种语法让 id_list 列出的 identifier 能代换成 token_sequence.

  范例:

/* 造出一个有 40 个元素的整数数组, 并将所有元素的值初始化为其编号的两倍. 即 stack[0] = 0, stack[1] = 2, stack[2] = 4 ....以此类推. */
#define STACKSIZE       40 
#define INITCELL(x)     2 * x 

int *stack; 

create() { 
    int i; 
    stack = allocate(STACKSIZE); 
    for (i = 0; i < STACKSIZE; i++) stack[i] = INITCELL(i);
}
  最后, 有时会用到清除定义 (undefine) [让编译器 (compiler) 别理会此定义]. 这样就用到下面的命令.
语法 : #undef identifier
  说明:

  #undef 可以清除一个根本不存在的 identifier.



编译条件


  这些命令可以让您的程序更具有可塑性 (flexibility). 利用 identifier 定义与否, 可以为不同的目的而变化源代码. 用途像是挑选系统管理员连线、支援多个驱动程序 (或不同版本的驱动程序).
  语法: 

#ifdef  
#ifndef  
#if  
#elif  
#else 
#endif
  说明:

   是一个已经定义 (或应该定义) 的 identifier. 它应于您的程序或是已经引用的文件事先定义, 不然就是驱动程序已定义的符号 (symbol).

   是一个常数运算式 (constant expression), 计算布林 (boolean) 逻辑条件. 运算式中, 可以在合于语法的情形下, 使用下面的组合:

  运算符: ||, &&, >>, <<, +, -, *, /, %, &, |, ^, !, ~, ==, !=, <, >, <=, >=, ?: 

  用来分组的小括号: (, )

  调用形式: defined(identifier) 以及 identifiers 
#ifdef identifier
可以视为这行的缩写:
#if defined(identifier)

#ifndef identifier
可以视为这行的缩写:
#if !defined(identifier)

#elif expression
可以视为这些的缩写:
#else 
#   if expression 
#   endif
范例 1: 

/* 使用 #if 0 可以让你在一段源代码中加上注解 (comment). 
   这样做的其中一个理由是把旧的源代码保留在原位, 防止新的程序失败. */
#if 0
/* 在此, 常数运算式算出 (或说本来就是) 0, 所以此段源代码不予编译. */
     write(user_name + " 有 " + total_coins + " 元.\n");
#else
/* 这是另外的情形 (if 算出零值, else 就是非零值), 所以会编译此段程序. */
     printf("%s 有 %d 元\n", user_name, total_coins);
#endif

范例 2: 
// 这个范例由 TMI 的 /adm/simul_efun/system.c 改写而来.
#ifdef __VERSION 
    string version() { return __VERSION__; }
#elif defined(MUDOS_VERSION) 
    string version() { return MUDOS_VERSION; }
#else 
#   if defined(VERSION) 
        string version() { return VERSION; }
#   else 
        string version() { return -1; }
#   endif 
#endif



除错


  #echo 命令让您向驱动程序的 stderr (STanDard ERRor, 标准错误处理) 印出消息. 这项功能在诊断和除错时非常有用.
语法: 
#echo This is a message
说明: 
#echo 这行就是消息的内容, 并逐字印出. 消息前后不用加上 ".



特定的编辑器功能


  这项是驱动程序内建的功能.
语法: #pragma keyword
  目前可用的 keyword 列在下面:
strict_types 
save_binary 
save_types 
warnings 
optimize 
error_context 
  使用 #pragma no_keyword 可以关闭指定的功能.

  说明:

  'strict_types' 告诉编译器调用 call_other() 的函数, 其返回值不可忽略.

  'save_binary' 告诉编译器要储存此物件的二进位 (binary) 档. 在重新启动或关闭游戏之后, 载入物件的时间会变快, 因为物件已经储存为二进位档, 不必重新编译.

  'save_types' 目前停用

  'warnings' 在您的 LPC 源代码开启一些警告措施. 这些警告不见得会依照您预料中的结果反应.

  'optimize' 用一点时间改进编译过的源代码效率.

  'error_context' 于错误消息中使用更多的文字指示哪一行发生错误.



快速文章格式


  这项功能便于求助消息、房间语句等长篇内容使用文章格式.
语法 1 :
@marker 
<... text block ...> 
marker

语法 2 :
@@marker 
<... text block ...> 
marker

Notes: 

@  - 产生一个适于 write() 的字符串.
@@ - 产生一个字符串数组, 适于分页文章 (body pager).
  在结束标记 (end marker) 之前, 使用 @marker 或 @@marker. 两者之间是您想对使用者显示的文章. 文章以 marker 作为结束, 不必加 @ 或 @@. 使用 @, 文章就如同一个字符串, 换行处加上 \n. 使用 @@, 文章就如同一个字符串数组, 而每一行分别是一个字符串.
范例 1 : 

int help() { 
    write( @ENDHELP
这是求助文章。 
It's hopelessly inadequate. 
ENDHELP 
); 
    return 1;
}

与此相同:
int help() { 
    write( "这是求助文章。\nIt's hopelessly inadequate.\n" ); 
    return 1;
}

范例 2 : 
int help() { 
    this_player()->more( @@ENDHELP
这是求助文章。 
It's hopelessly inadequate. 
ENDHELP 
, 1); 
    return 1;
}

与底下相同:
int help() { 
    this_player()->more( ({ "这是求助文章。", 
                            "It's hopelessly inadequate." }), 1); 
    return 1;
}

翻译: Spock @ FF 97.Aug.9.

[回到顶部
天下创作室