基于 C 语言的 JavaScript 引擎探索

和其他的 JavaScript 引擎一样,SpiderMonkey 不直接提供像 DOM 这样的对象,而是提供解析,执行 JavaSccript 代码,垃圾回收等机制。SpidlerMonkey 是一个在 Mozilla 之下的开源项目,要使用 SpiderMonkey,需要下载其源码,然后编译为静态 / 动态库使用。

要在自己的应用程序中使用 SpiderMonkey,首先需要了解以下三个核心概念:

运行时环境运行时环境是所有 JavaScript 变量,对象,脚本以及代码的上下文所存在的空间。每一个上下文对象,以及所有的对象均存在于此。一般应用仅需要一个运行时即可。

上下文上下文即脚本执行的环境,在 SpiderMonkey 中,上下文可以编译执行脚本,可以存取对象的属性,调用 JavaScript 的函数,转换类型,创建 / 维护对象等。几乎所有的 SpiderMonkey 函数都需要上下文作为其第一个参数 (JSContext *)。

上下文与线程密不可分,一般来讲,单线程应用可以使用一个上下文来完成所有的操作,每一个上下文每次只能完成一个操作,所有在多线程应用中,同一时刻只能有一个线程来使用上下文对象。一般而言,多线程应用中,每个线程对应一个上下文。

全局对象全局对象包含 JavaScript 代码所用到的所有类,函数,变量。在 DOM 操作中,我们使用的:

 alter("something");

事实上使用的是全局变量 window 的一个属性 alter( 这个属性正好是一个函数 ),事实上上边的语句在执行时会别解释为:

 window.alter("something");

三者的关系如下图所示:

图 1. 引擎内部结构依赖关系
 

安装 SpiderMonkey

首先从 SpiderMonkey 的代码库中下载其源码包 js-1.7.0.tar.gz 本文在 Linux 环境下编译,SpiderMonkey 的编译安装很容易:

 # 解压缩
 tar xvzf js-1.7.0.tar.gz 

 # 切换至源码目录
 cd js-1.7.0/src 

 # 编译
 make -f Makefile.ref

编译完成之后,会生成一个新的目录,这个目录的名称依赖于平台,比如在 Linux 下,名称为:Linux_All_DBG.OBJ,其中包含静态链接库 libjs.a 和动态链接库 libjs.so 等。本文后续的编译环境就需要依赖于我们此处编译出来的库文件。应该注意的是,此处编译出来的库文件包含对调试的支持,体积较大,在应用程序发布时,可以去掉这些调试支持,使用下列重新编译库:

 # 创建非 debug 模式的库
 make BUILD_OPT=1 -f Makefile.ref

Windows 及其他平台的编译此处不再赘述,读者可以自行参考 SpiderMonkey 的官方文档。

JavaScript 对象与 C 对象间的转换关系

JavaScript 是一门弱类型的语言,变量的值的类型在运行时才确定,而且可以在运行时被修改为其他类型的变量;而 C 语言,是一门静态类型的语言,变量类型在编译时就已经确定。因此,这两者之间变量的互访就有了一定的难度,SpiderMonkey 提供了一个通用的数据类型 jsval 来完成两者之间的交互。

事实上,在 C 代码中定义的 jsval 类型的变量可以是 JavaScript 中的字符串,数字,对象,布尔值,以及 null 或者 undefined。基于这个类型,SpiderMonkey 提供了大量的类型判断及类型转换的宏和函数。可以参看下表:

表 1. JavaScript 对象与 C 对象转换表

JavaScript 类型 jsval 类型判断 jsval 常量 jsval 转化
null JSVAL_IS_NULL(v) JSVAL_NULL
Undefined JSVAL_IS_VOID(v) JSVAL_VOID
Boolean JSVAL_IS_BOOLEAN(v) JSVAL_TRUE, 
JSVAL_FALSE, 
BOOLEAN_TO_JSVAL(b)
JSVAL_TO_BOOLEAN(v)
number JSVAL_IS_NUMBER(v), 
JSVAL_IS_INT(v), 
JSVAL_IS_DOUBLE(v)
INT_TO_JSVAL(i), 
DOUBLE_TO_JSVAL(d)
JSVAL_TO_INT(v), 
JSVAL_TO_DOUBLE(v)
string JSVAL_IS_STRING(v) STRING_TO_JSVAL(s) JSVAL_TO_STRING(v), 
JS_GetStringChars(s), 
JS_GetStringLength(s)
object JSVAL_IS_OBJECT(v) 
&& JSVAL_IS_NULL(v)
OBJECT_TO_JSVAL(o) JSVAL_TO_OBJECT(v)

应该注意的是,jsval 有一定的缺陷:

  • jsval 并非完全的类型安全,在进行类型转换之前,你需要明确被转换的对象的真正类型,比如一个变量的值为 number 类型,而对其做向字符串的转化,则可能引起程序崩溃。解决方法是,在转换之前,先做判断。
  • jsval 是 SpiderMonkey 垃圾回收机制的主要目标,如果 jsval 引用一个 JavaScript 对象,但是垃圾收集器无法得知这一点,一旦该对象被释放,jsval 就会引用到一个悬空指针。这样很容易使得程序崩溃。解决方法是,在引用了 JavaScript 对象之后,需要显式的告知垃圾收集器,不引用时,再次通知垃圾收集器。

简单示例

基本代码模板

基本流程

使用 SpiderMonkey,一般来讲会使用以下流程:

  • 创建运行时环境
  • 创建一个 / 多个上下文对象
  • 初始化全局对象
  • 执行脚本,处理结果
  • 释放引擎资源

在下一小节详细说明每个流程

代码模板

使用 SpiderMonkey,有部分代码是几乎每个应用程序都会使用的,比如错误报告,初始化运行时环境,上下文,全局变量,实例化全局变量等操作。这里是一个典型的模板:

清单 1. 必须包含的头文件

#include "jsapi.h"

引入 jsapi.h,声明引擎中的所用到的记号,结构体,函数签名等,这是使用 SpiderMonkey 所需的唯一一个接口文件 ( 当然,jsapi.h 中不可能定义所有的接口,这些文件在 jsapi.h 头部引入 jsapi.h,如果对 C 语言的接口,头文件引入方式不熟悉的读者,请参阅相关资料 )。

清单 2. 全局变量声明

 /* 全局变量的类声明 */
static JSClass global_class = {
    "global",
    JSCLASS_GLOBAL_FLAGS,
    JS_PropertyStub,
    JS_PropertyStub,
    JS_PropertyStub,
    JS_PropertyStub,
    JS_EnumerateStub,
    JS_ResolveStub,
    JS_ConvertStub,
    JS_FinalizeStub,
    JSCLASS_NO_OPTIONAL_MEMBERS
 };

JSClass 是一个较为重要的数据结构,定义了 JavaScript 对象的基本结构 ---“类”,这个类可以通过 SpiderMonkey 引擎来实例化为对象。JS_PropertyStub 是 JS_PropertyOp 类型的变量,这里的 JS_PropertyStub 是为了提供一个默认值。JS_PropertyOp 可以用做对象的 setter/getter 等的,这些内容我们将在后边的章节详细讨论。

清单 3. 错误处理函数

 /* 错误处理函数,用于回调,打印详细信息 */
 void report_error(JSContext *cx,  const char *message, JSErrorReport *report){
    fprintf(stderr, "%s:%u:%s\n",
    		 report->filename ? report->filename : "<no filename>",
            (unsigned int) report->lineno,
            message);
 }

定义好这些结构之后,我们需要实例化这些结构,使之成为内存对象,流程如下:

清单 4. 主流程

				int main(int argc, char *argv[]){
    JSRuntime *runtime;
    JSContext *context;
    JSObject *global; 

	 // 创建新的运行时 8M
    runtime = JS_NewRuntime(8L * 1024L * 1024L);
    if (runtime == NULL){
        return -1;
    } 

	 // 创建新的上下文
    context = JS_NewContext(runtime, 8*1024);
    if (context == NULL){
        return -1;
    } 

	 //
    JS_SetOptions(context, JSOPTION_VAROBJFIX);
    // 设置错误回调函数 , report_error 函数定义如上
	 JS_SetErrorReporter(context, report_error); 

	 // 创建一个新的 JavaScript 对象
    global = JS_NewObject(context, &global_class, NULL, NULL);
    if (global == NULL){
        return -1;
    } 

	 // 实例化 global, 加入对象,数组等支持
    if (!JS_InitStandardClasses(context, global)){
        return -1;
    } 

	 //
	 // 使用 global, context 等来完成其他操作,用户定制代码由此开始
	 // 

	 // 释放上下文对象
    JS_DestroyContext(context);
	 // 释放运行时环境
    JS_DestroyRuntime(runtime);
	 // 停止 JS 虚拟机
    JS_ShutDown(); 

	 return 0;
 }

用户自己的代码从上边代码中部注释部分开始,用户代码可以使用此处的 context 对象及预设过一定属性,方法的 global 对象。

执行 JavaScript 代码

执行 JavaScript 代码片段

执行 JS 最简单的方式,是将脚本作为字符串交给引擎来解释执行,执行完成之后释放临时的脚本对象等。SpiderMonkey 提供一个 JS_EvaluateScript 函数,原型如下:

清单 5. 执行 JS 代码的函数原型

 JSBool JS_EvaluateScript(JSContext *cx, JSObject *obj,
    const char *src, uintN length, const
				char *filename,
    uintN lineno, jsval *rval);

使用这个函数,需要提供上下文,全局变量,字符串形式的脚本,脚本长度及返回值指针,脚本名和行号参数可以填空值 ( 分别为 NULL 和 0)。如果函数返回 JS_TRUE,表示执行成功,执行结果存放在 rval 参数中,否则执行失败,rval 中的值为 undefined。我们可以具体来看一个例子:

清单 6. 执行 JS 代码片段

				char *script = "(function(a, b){return a * b;})(15, 6);";
	 jsval rval; 

	 status = JS_EvaluateScript(context, global, script, strlen(script)\
	        , NULL, 0, &rval); 

	 if (status == JS_TRUE){
	    jsdouble d;
	    JS_ValueToNumber(context, rval, &d);
	    printf("eval result = %f\n", d);
	 }

执行结果为:

 eval result = 90.000000

编译 JavaScript 代码

通常,我们可能会多次执行一段脚本,SpiderMonkey 可以将脚本编译成 JSScript 对象,然后可以供后续的多次调用。现在来看一个例子,使用 C 代码编译一个 JavaScript 脚本,然后运行这个脚本。

清单 7. 从文件加载并执行脚本

 JSBool evalScriptFromFile(JSContext *cntext, const
	char *file){
    JSScript *script;
    JSString *jss;
    JSBool status;
    jsval value; 

    //get the global object
    JSObject *global = JS_GetGlobalObject(context); 

    //compile the script for further using
    script = JS_CompileFile(context, global, file); 

    if (script == NULL){
        return JS_FALSE;
    } 

    //execute it once
    status = JS_ExecuteScript(context, global, script, &value);
    jss = JS_ValueToString(context, value);
    printf("eval script result is : %s\n", JS_GetStringBytes(jss)); 

    //destory the script object
    JS_DestroyScript(context, script); 

    return status;
 }

这里传递给函数 evalScriptFromFile的 JSContext* 参数为外部创建好的 Context 对象,创建的方法参看上一节。

清单 8. 执行

 JSBool status = evalScriptFromFile(context, "jstest.js");
 if (status == JS_FALSE){
        fprintf(stderr, "error while evaluate the script\n");
 }

假设我们将如下脚本内容保存进一个脚本 jstest.js:

清单 9. jstest.js 脚本内容

				varPerson = function(name){
    var _name_ = name;
    this.getName = function(){
        return _name_;
    } 

    this.setName = function(newname){
        _name_ = newname;
    }
 } 

 varjack = new Person("jack");
 jack.setName("john");
 // 最后一句将作为脚本的执行结果返回给 C 代码
 jack.getName();

jack 对象的名字现在设置为了”john”, 脚本的最后一条语句的值将作为脚本的返回值返回到 C 代码处,并打印出来:

 eval script result is : john

C 与 JavaScript 的交互

C 程序调用 JavaScript 函数

由于两者的数据类型上有较大的差异,因此无法直接从 C 代码中调用 JavaScript 代码,需要通过一定的转化,将 C 的变量转换为 JavaScript 可以设别的变量类型,然后进行参数的传递,返回值的处理也同样要经过转换。

我们在 JavaScript 中定义一个函数 add,这个函数接受两个参数然后返回传入的两个参数的和。定义如下:

清单 10. JavaScript 版本的 add

				function add(x, y){
    return x + y;
 }

然后,我们在 C 语言中根据名称调用这个 JS 函数:

清单 11. 从 C 代码中调用 JavaScript 函数

 JSBool func_test(JSContext *context){
    jsval res;
    JSObject *global = JS_GetGlobalObject(context);
    jsval argv[2]; 

    //new 2 number to pass into the function "add" in script
    JS_NewNumberValue(context, 18.5, &res);
    argv[0] = res;
    JS_NewNumberValue(context, 23.1, &res);
    argv[1] = res; 

    JS_CallFunctionName(context, global, "add", 2, argv, &res); 

    jsdouble d; 

    //convert the result to jsdouble
    JS_ValueToNumber(context, res, &d);
    printf("add result = %f\n", d); 

    return JS_TRUE;
 }

这里需要注意的是,JS_CallFunctionName 函数的参数列表:

清单 12. JS_CallFunctionName 原型

 JSBool  JS_CallFunctionName(JSContext *cx, JSObject *obj,
 const char *name, uintN argc, jsval *argv, jsval *rval);

表 2. JS_CallFunctionName 参数列表含义

名称 类型 类型描述
cx JSContext * 上下文定义
obj JSObject * 调用该方法的对象
name const char * 函数名
argc uintN 函数参数个数
argv jsval * 函数实际参数形成的数组
rval jsval * 返回值

参数中的 argv 是一个 jsval 形成的数组,如果直接传递 C 类型的值,则很容易出现 core dump(Linux 下的段错误所导致 ),因此,需要 JS_NewNumberValue 函数转换 C 语言的 double 到 number( 原因见对象转换小节 )。

JavaScript 程序调用 C 函数

从 JS 中调用 C 函数较上一节为复杂,我们来看一个较为有趣的例子:SpiderMonkey 中原生的 JavaScript 的全局变量中没有 print 函数,我们可以使用 C 的 printf 来实现这个功能。我们定义了一个函数 print, print 使用 logging 函数,而 logging 函数是定义在 C 语言中的,接受一个字符串作为参数,打印这个字符串到标准输出上 :

清单 13. JavaScript 调用 C 函数

 //log user log in information
 logging("user jack login on 2010/7/6"); 

 //user do nothing else
 nothing(); 

 //log user log out information
 logging("user jack logout on 2010/7/7"); 

 function print(){
    for (vari = 0; i < arguments.length; i++){
        logging(arguments[i]);
    }
 } 

 print("hello", "all", "my", "friend");

在 C 语言中,我们定义 logging 函数和 nothing 函数的原型如下:

清单 14. C 函数的实现

 /**
 * define an exposed function to be used in scripts
 * print out all the incoming arguments as string.
 */
 static JSBool  logging(JSContext *context, JSObject *object, uintN argc,
        jsval *argv, jsval *value){
    int i = 0;
    JSString *jss; 

    for(i = 0; i < argc; i++){
       jss = JS_ValueToString(context, argv[i]);
       printf("message from script environment : %s\n", \
               JS_GetStringBytes(jss));
    }
    return JS_TRUE;
 } 

 /**
 * define an exposed function to be used in scripts
 * do nothing but print out a single line.
 */
 static JSBool  nothing(JSContext *context,
 JSObject *object, uintN argc, jsval *argv, jsval *value)
 {
    printf("got nothing to do at all\n");
    return JS_TRUE;
 }

从函数的签名上可以看出,C 中暴露给 JS 使用的函数,参数的个数,及对应位置上的类型,返回值都是固定的。所有的从 C 中暴露给 JS 的函数都需要“实现这个接口”。

定义好了函数之后,还需要一些设置才能在 JS 中使用这些函数。首先定义一个 JSFunctionSpec 类型的数组,然后通过 JS_DefineFunctions 将这些函数放到 global 对象上,然后在 JS 代码中就可以访问上边列出的 C 函数了。具体步骤如下:

清单 15. 注册函数列表

	static JSFunctionSpec functions[] = {
    {"logging", logging, LOG_MINARGS, 0, 0},
    {"nothing", nothing, NOT_MINARGS, 0, 0},
    {0, 0, 0, 0, 0}
 }; 

    //define function list here
    if (!JS_DefineFunctions(context, global, functions)){
        return -1;
 }

运行结果如下:

 message from script environment : user jack login on 2010/7/6
 got nothing to do at all
 message from script environment : user jack logout on 2010/7/7
 message from script environment : hello
 message from script environment : all
 message from script environment : my
 message from script environment : friend

在 C 程序中定义 JavaScript 对象

在 SpiderMonkey 中,在 JavaScript 中使用由 C 语言定义的对象较为复杂,一旦我们可以定义对象,使得两个世界通过 JS 交互就变得非常简单而有趣,很容易使用这样的方式来定制我们的应用,在系统发布之后仍然可以轻松的修改系统的行为。

首先,我们要定义好基本的数据结构,即我们要暴露给 JS 世界的对象的属性,结构;然后,使用 JSAPI 定义这个对象的属性;然后,使用 JSAPI 定义对象的方法;最后,创佳这个对象,并绑定其属性表和方法列表,放入全局对象。

假设我们有这样一个数据结构,用来表述一个人的简单信息 :

清单 16. PersionInfo 结构

 typedef struct{
    char name[32];
    char addr[128];
 }PersonInfo;

定义属性表为枚举类型:

清单 17. 属性表

enum person{
    NAME,
    ADDRESS
 };

我们需要将 C 语言原生的数据结构定义为 JSAPI 所识别的那样:

清单 18. 属性定义

 //define person properties
 JSPropertySpec pprops[] = {
    {"name", NAME, JSPROP_ENUMERATE},
    {"address", ADDRESS, JSPROP_ENUMERATE},
    {0}
 };

清单 19. 方法定义

 //define person methods
 JSFunctionSpec pfuncs[] = {
    {"print", printing, 0},
    {"getName", getName, 0},
    {"setName", setName, 0},
    {"getAddress", getAddress, 0},
    {"setAddress", setAddress, 0},
    {0}
 };

清单 20. 类定义

 //define person class (JSClass)
 JSClass pclass = {
    "person", 0,
    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
 };

一旦这些基本信息定义好 (pfuncs 数组中的 getter/setter 的实现比较简单,这里由于篇幅不列出代码,感兴趣的朋友可以参看附录 ),我们就可以实例化它,并将其放入上下文中,使得 JS 代码可以访问。

清单 21. 定义对象及对象的属性,方法

    JSObject *person; 

    //define the object
    person = JS_DefineObject(\
            context, global, "person", &pclass, 0, JSPROP_ENUMERATE); 

    //install the properties and methods on the person object
    JS_DefineProperties(context, person, pprops);
    JS_DefineFunctions(context, person, pfuncs);

这样,在 JavaScript 代码中,我们就可以通过 person 这个标识符来访问 person 这个对象了:

清单 22. 测试脚本

 //undefined of course
 person.print(); 

 //person.name = "abruzzi";
 //person.address = "Huang Quan Road"; 

 person.setName("Desmond");
 person.setAddress("HuangQuan Road"); 

 //print is global function, access properties directly
 print("person name = " + person.name);
 print("person address = " + person.address); 

 person.print(); 

 (function(){
    //using getter/setter to access properties
    return person.getName() + " : " + person.getAddress();
 })();

对运行结果如下:

 name : undefined
 address : undefined
 person name = Desmond
 person address = HuangQuan Road
 name : Desmond
 address : HuangQuan Road
 eval script result is : Desmond : HuangQuan Road

结束语

本文中详细讨论了如何使用基于 C 的 JavaScript 引擎:SpiderMonkey 的用法。包括最基本的代码模板,C 代码与 JavaScript 代码之间的交互,以及在 C 代码中定义 JavaScript 对象等内容,使用这些基本概念,很容易将实现应用程序的脚本化。在实际的应用中,可以将应用程序的部分组件 ( 提供给用户自定义的组件 ) 暴露给 JavaScript 访问,或者在 JavaScript 脚本中提供函数的存根 ( 仅仅定义函数的原型 ),用户可以通过实现这些函数的具体逻辑,来实现脚本化。

下载

描述 名字 大小 下载方法
样例代码 jsfun.zip 8KB HTTP

关于下载方法的信息

时间: 2024-12-10 14:15:43

基于 C 语言的 JavaScript 引擎探索的相关文章

silverlight线程与基于事件驱动javascript引擎(实现轨迹回放功能)_javascript技巧

案例背景: 整个功能其实就是从数据库取出数据,然后在界面上播放,简单地说就是类似网上在线看视频,听音乐,只不过我取的是字符串数据,而他们取的是流文件数据.把整体数据分成十份,十个线程同时向数据库取数据(并发提高速度)放在十个队列中,另外一个线程从队列中取数据拿出来到界面上播放,可以拖动播放进度,停止,暂停,重新播放,控制播放速度.恩,功能听起来似乎很简单,做起来也不是很难.但是后面发现的一些问题,以及顺着这些问题往下挖掘,挖掘了一些我认为值得记住的东西. 关键东西: 1. siliverligh

微软的 JavaScript 引擎将很快支持 Asm.js

几年前 Mozilla 开发了 asm.js ,这是一个 JavaScript 的子集,可以让 JavaScript 代码执行更快速.知道今天 asm.js 的所有优化都是针对 Firefox 浏览器的,不过很快该技术也将得到微软最新的来自 Windows 10 的 Chakra JavaScript 引擎的支持. 微软今天宣布,对 asm.js 的支持是 10 个开发者最强烈要求的特性之一,因此 Chakra 团队决定实现它.Chakra 团队称:在过去数月我们密切研究了 asm.js 以及其

功能强大的JavaScript引擎--SpiderMonkey

JavaScript是由Netscape开发的对象脚本语言,其特点是开发简单.功能灵活,目前已广泛应用于WEB页面及服务器应用程序中.HTML本身是静态的.不允许用户干预,但用JavaScript编写的脚本程序就可以在用户的浏览器端运行,可以同用户进行交互,从而实现动态页面.可以将JavaScript与嵌入WEB的大多数对象的事件(如鼠标点击.移动等)相关联,然后用自己的方式处理这些事件.JavaScript提供了丰富的内置函数及命令,能在浏览器中显示HTML.数值计算.多媒体播放.超级链接以及

一起谈.NET技术,.NET平台上的JavaScript引擎

长久以来,在.NET平台上只能通过JScript.NET执行ECMAScript/JavaScript代码,但是该项目一直是.NET语言中的二等公民,甚至Mono中的对应项目也已经无人维护.不过在JScript.NET逐渐淡出人们视线的时候,.NET平台上也出现了一些新的JavaScript执行引擎,虽不完善,但值得关注. Jint是一个相对较早的纯托管代码实现的JavaScript执行引擎,基于MIT授权协议开源,它的目标是为.NET应用程序提供JavaScript代码的执行及互操作能力.您可

c语言-基于C语言,用蚁群算法求最优路径。百度复制粘贴的别来了。。。要求可以直接运行的代码哈

问题描述 基于C语言,用蚁群算法求最优路径.百度复制粘贴的别来了...要求可以直接运行的代码哈 一个人从上海大学出发,经过若干个地点,路线不重复走,最后回到上海大学,找三条优化路线. 上海大学:北纬N31°19′5.86″ 东经E121°23′21.52″ 星雨城:北纬N31°19′46.58″ 东经E121°24′9.29″ 大康公寓:北纬N31°19′18.88″ 东经E121°25′3.98″ 文景楼:北纬N22°35′23.78″ 东经E113°52′50.67″ 大场中学:北纬N31°

威胁预警通告 JavaScript引擎MuJS爆出堆栈溢出漏洞 请尽快升级最新版本

MuJS近日曝出多个堆溢出漏洞,绿盟科技给出的威胁预警级别为低级,这意味着影响较小,危害程度较小.修复方法请下载使用最新版本的MuJS: 1.使用git命令进行最新源码下载 "git clone git://git.ghostscript.com/mujs.git" 2.或到官网进行下载,链接如下https://github.com/ccxvii/mujs JavaScript引擎MuJS漏洞描述 Bug 697136 提交时间:2016年9月20日 POC及其详情见如下链接: htt

基于C语言实现的迷宫游戏代码_C 语言

本文实例讲述了基于C语言实现迷宫游戏的方法,代码备有较为详尽的注释,便于读者理解.通过该游戏代码可以很好的复习C语言的递归算法与流程控制等知识,相信对于学习游戏开发的朋友有一定的借鉴价值. 完整的实例代码如下: #include <graphics.h> #include <stdlib.h> #include <stdio.h> #include <conio.h> #include <dos.h> #define N 20/*迷宫的大小,可改

Duktape:一个新的小巧的超精简可嵌入式JavaScript引擎

Duktape是一个可嵌入的Javascript引擎,主要关注便携性和精简及紧凑性. Duktape很容易集成到C/C++项目: 添加duktape.c和duktape.h到您的build中,并使用Duktape API从C代码中,调用ECMAScript代码的功能,反之亦然. 主要特性: 嵌入式,便携,小巧:     200kB的代码     46KB RAM启动(X86,默认选项)     22KB RAM启动(X86,lowmem选项)     42kLoC源(不包括注释等)     可以

写给小白的JavaScript引擎指南_javascript技巧

关于本文标题,我并不认为参与写或者读本文的人是白痴.但是有时某个话题会让你觉得自己就像个白痴一样,而 JavaScript 引擎就是这些话题之一,至少对于我来说是这样. 有时编写 Web 应用的代码会感觉充满魔力,因为我们只是写了一系列字符,就能在浏览器里看到效果了.但是理解魔法背后的技术,可以帮助你更好地提高编程技巧.至少当你试图解释在 JavaScript 驱动的 web 或移动应用的幕后发生了什么的时候,会觉得自己不那么白痴了. 很多年前,那是我还是个研究生讲师,向一个教授抱怨还没有掌握那