




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、2004.11.3,AI程序设计课件,1,第15章 与其他编程语言接口,2004.11.3,AI程序设计课件,2,第15章 与其他编程语言接口,本章介绍Visual Prolog与其他编程语言的接口,帮助读者学会如何在Visual Prolog中调用WIN32 API,打开更广阔的编程世界的大门。,2004.11.3,AI程序设计课件,3,第15章 与其他编程语言接口,15.1 外部代码 15.2 关键问题 15.3 调用约定和链接名 15.4 数据表示 15.5 存储管理 15.6 Win32 API函数,2004.11.3,AI程序设计课件,4,15.1 外部代码,所谓“外部代码”是指用其
2、它编程语言(而不是用Visual Prolog)所编写的代码。 Visual Prolog能直接调用其它语言代码。本章就来解释这些概念和细节。直接调用外部代码是一种二进制级的底层调用,而非高级语言层面的高级调用。这在简单的例程中相当简单,但也可能出奇的复杂。可以肯定的一点是:处理复杂调用需要非常熟悉Visual Prolog和其它编程语言。但是不要担心,实际上,在许多例程中所需要的交互是相当简单的,2004.11.3,AI程序设计课件,5,15.2 关键问题,其它语言编译器和Visual Prolog编译器有很大的不同,这是由于它们是由不同的人所制作的,而且它们必须支持不同的语言特性。Visu
3、al Prolog不可能和所有的外部语言代码交互,因为它不可能知道其他编译器所采用的规则。所以,要实现Visual Prolog和其他语言代码的交互,就要求这些代码必须遵循规定的方式。 为了调用外部代码(异种语言代码),我们就必须访问这些代码。本章我们要处理的代码是直接链接到程序里,或者位于一个动态连接库DLL中。,2004.11.3,AI程序设计课件,6,15.2 关键问题,首先,我们必须查找这些代码的位置。这通过一个名字来实现。如果代码是直接链接到你的程序里,就必须使用链接名;如果代码位于一个DLL,则可以使用导出名。无论是用链接名还是用导出名,对Visual Prolog来说没有区别,但
4、是当你试图在外部代码(或系统)中寻找这个名字时,就有了区别。我们这里提到系统,是因为有时你必须使用的名字在代码中根本不存在。因此,对于这个概念,我们仅使用链接名。,2004.11.3,AI程序设计课件,7,15.2 关键问题,其次,在我们已经确定了外部代码的位置之后,接着必须传递输入参数并调用代码,代码被执行后,还必须获取其输出等等。有许多不同的途径去完成此过程。显然,调用者和被调用者必须在这一点达成一致,即双方必须有调用约定。 第三,关于数据表示。但是,不仅调用双方必须在参数等的传递上相一致,更重要的是双方要以相同方式解释所传递的字节。换句话说就是,双方的数据表示必须相同。,2004.11.
5、3,AI程序设计课件,8,15.2 关键问题,最后要注意的一点是内存管理。调用者和被调用者必须明确在必要时由哪一方分配和释放内存。如果释放内存和分配内存不是由同一方进行,那么释放内存一方必须以正确的方式释放内存。 总之,调用外部代码有四个关键问题需要考虑: 链接名 调用约定 数据表示 存储管理,2004.11.3,AI程序设计课件,9,15.3 调用约定和链接名,链接名(或导出名)用于识别你想要调用的代码。不同的编译器用不同的缺省链接名,许多编译器有多种指定链接名的途径。在Visual Prolog中,你可以用保留字“as”为一个谓词声明一个链接名。如: predicates pppp : (
6、integer) as LinkName. 在Visual Prolog程序中,上面的谓词被命名为“pppp”,但是它的链接名是“LinkName”。,2004.11.3,AI程序设计课件,10,15.3 调用约定和链接名,注意:仅类谓词有一个链接名,这意味着它必须在一个类中进行声明或在一个类实现的类谓词(class predicates)段进行声明。 Visual Prolog支持大量不同的调用约定。这些约定也在谓词中声明,但用的是language保留字。 predicates qqqq : (integer) language c.,2004.11.3,AI程序设计课件,11,15.3 调
7、用约定和链接名,按照C编译器的调用约定,编译器在C程序中的名字前添加一个下划线来创建链接名。如果你用C调用约定但不提供链接名,Visual Prolog也将使用这个约定。注意:一直到build 6107编译器实际上使用的是另一种命名策略,也就是说你必须用as来获取链接名。上例中qqqq的链接名是“_qqqq”。如果你声明一个链接名,就必须严格遵守这个规则: predicates rrrr : (integer) language c as LinkName. rrrr将用这个C调用约定,并有一个链接名LinkName(即没有下划线)。,2004.11.3,AI程序设计课件,12,15.3 调用
8、约定和链接名,C+编译器通常用的是C调用约定,但是它们不依赖C链接名,因为C+允许重载。也就是说,在C+中相同的名字只要变量数目不同或者和类型不同,就可以看作为不同的函数使用。这些不同变量必须有不同的链接名。因此C+编译器具有完善的命名机制,这种命名基于C+名字、变量的数目和类型。这个过程可称为“命名熨烫(name mangling)”。 不同的编译器采用不同的命名熨烫算法,从而互不兼容。通常情况下,在被作为外部代码访问的C+程序中要使用明确的链接名,或者在一个输出“C”部分封装这个声明,使编译器使用C命名约定。,2004.11.3,AI程序设计课件,13,15.3 调用约定和链接名,Visu
9、al Prolog也支持stdcall调用约定。Microsoft Visual Basic使用stdcall作为Microsoft Win32平台API调用的调用约定,许多Pascal家族编译器,包括Borland Delphi也使用stdcall。实际上C和C+程序和其他语言的程序接口时,通常也使用stdcall调用约定。Visual Prolog对stdcall调用约定使用与C调用相同的命名约定。 注意:直到build 6107编译器实际上使用的是另一种命名策略,因此必须用as来获取链接名。即在Prolog名字前面加前缀下划线来创建链接名,但是如果指定了一个链接名,它将被严格使用。,20
10、04.11.3,AI程序设计课件,14,15.3 调用约定和链接名,Microsoft Win32 API使用特殊的stdcall调用约定,它较C调用约定多了一些名字修饰。可参阅Visual Prolog语言参考手册。Visual Prolog有一个专用的调用约定apicall来支持这个特殊的stdcall。apicall和stdcall仅在名字修饰上有不同之处。有了apicall,用as声明的外部链接名也要被修饰。若需要一个有不同修饰的名字,就必须用stdcall并自己指定修饰名。,2004.11.3,AI程序设计课件,15,15.4 数据表示,所输入的数字参数按其值进行传递,即数值直接压入
11、调用堆栈。输出数字参数通过引用传递,即结果指针被压入调用堆栈。调用堆栈中整型数占32位,实型数占64位。 字符也可以用数字表示。 其他数据用一个指针来指向。通过直接将指针压入调用堆栈来传递输入参数。通过压入结果指针的指针(即指向指针的指针)来传递输出参数。,2004.11.3,AI程序设计课件,16,15.4 数据表示,一个算符的论域由指向一块内存的指针来表示,这块内存首先保存了算符,随后是每一个子部件。这些子部件直接由一个数字或指向真实数据的指针来表示。 如果一个算符的论域只有一种选择,这种情况下通常具有相同的值,所以跳过这个算符。注意:在Visual Prolog 5中,除非该论域用str
12、uct关键字声明,否则该算符出现;而在Visual Prolog 6中,该算符永远不会出现。,2004.11.3,AI程序设计课件,17,15.4 数据表示,用align限定符可以使算符表示有所不同,请参阅语言参考的相关部分。 字符串由一个指针表示,它指向由零值空字符终止的字符序列,与C语言一样。 二进制论域由一个指针指向其二进制数据。其值等于数据长度加unsigned类型的大小,这个值紧接着存储在数据之前。,2004.11.3,AI程序设计课件,18,15.4.1 举例,假设想在Visual Prolog程序中调用一个C例程。在C中的声明如下: int myRoutine( wchar_t
13、* TheString, int BufferLength, wchar_t * TheResult ); “wchar_t *”是C语言中的unicode字符串。 这个函数有3个变量: TheString是一个字符串 Bufferlength是一个整型数 TheResult是一个字符串 该函数返回一个整型值。,2004.11.3,AI程序设计课件,19,15.4.1 举例,相应的Visual Prolog 6声明如下(假定它被声明在一个类中): class predicates myRoutine : ( string TheString, integer BufferLength, str
14、ing TheResult) - integer language c. 若谓词在类中声明,则“class”应去掉。,2004.11.3,AI程序设计课件,20,15.4.2 外部链接库,如果声明的谓词如上例所示,编译器就提示一个错误:找不到声明谓词的子句。 因为这个谓词根本不能在Visual Prolog中进行实现。这时必须通知编译器这个谓词的代码在外部(externally)某处。这里我们之所以使用externally这个单词,是因为它完全可以准确地表达在声明该谓词的类的实现中用一个所谓的求解限定符所要表达的意思。,2004.11.3,AI程序设计课件,21,15.4.2 外部链接库,如果
15、这个类命名为xxx,则它应该是: implement xxx resolve myRoutine externally . 这样编译器就接受了这个声明,但还可能出现链接错误: _myRoutine没有定义。 这是因为包含_myRoutine的库还没有链接。,2004.11.3,AI程序设计课件,22,15.4.2 外部链接库,如果_myRoutine位于一个静态库(一个LIB文件),则要把这个文件加入项目,链接器就会提取相关代码并加入程序。 如果_myRoutine位于一个DLL库,仍有一个LIB文件用以描述这个DLL,接着就把这个文件加入项目。在这种情况下,链接器在你的程序中放置信息,这些信
16、息告知在哪里可以找到DLL例程。,2004.11.3,AI程序设计课件,23,15.4.2 外部链接库,如果_myRoutine位于一个DLL库,但是没有对应的LIB文件,可以通过下面方式调用该例程: implement xxx resolve myRoutine externally from myDLL.dll . 这样,当myRoutine被首次调用时,编译器就增加代码,动态加载DLL库。这个DLL库在程序退出之前不卸载。 pfc/application/useDll可以用于动态加载和卸载DLL库,2004.11.3,AI程序设计课件,24,15.5 存储管理,数字和字符参数被直接压栈或
17、写入内存。这种情况比较简单。 然而,不直接压栈的数据涉及许多内存管理问题。因为只要调用双方的任一方要访问这个数据,数据都必须存在于内存。一旦数据不再需要,就必须回收内存以防止内存漏掉。 通常情况下,谁分配内存谁才能去回收这些内存,因为另一方并不知道如何回收。当然我们可以让双方采用相同的机制。例如,一方可以让另一方看到它的机制(如作为导出例程)。 Visual Prolog 6使用的内存分配例程是采用运行时间系统(Vip6kernel.dll)来实现的,并且可以从外部代码进行调用。 程序和库代码在处理何时回收内存时,通常采用一些事先已约定的方法。,2004.11.3,AI程序设计课件,25,15
18、.5.1 典型解决方案,这一节介绍解决内存管理问题的通用方法。不涉及COM和.NET,这是我们认为最为通用的方法。原理很简单: 输入参数仅在调用期间存活,所以,如果被调用者需要存储某一输入参数以备后用,它就必须将这个参数复制到自己的内存区。 输出被复制到调用者的内存缓冲区,所以被调用者分配的内存不会传送给调用者。 前面的myRoutine就是一个典型的例子。输出写入TheResult(由调用者分配的一个字符串),这就是为什么它看起来既是例程的输入又要传递BufferLength的原因。,2004.11.3,AI程序设计课件,26,15.5.1 典型解决方案,Visual Prolog 6程序调
19、用myRoutine例程: clauses p(TheString) = TheResult :- TheResult = string:create(bufferLength), RetCode = myRoutine(TheString, bufferLength, TheResult), checkRetCode(RetCode). sring:creat为字符串分配内存,myRoutine将它的结果复制到TheResult(Visual Prolog程序不涉及这些),它不回收任何已分配的内存。,2004.11.3,AI程序设计课件,27,15.5.2 垃圾收集和全局堆栈,如果不采用上面
20、的典型方案,Visual Prolog 6还提供一种全局性的G-堆栈,并且用一个垃圾收集箱来管理堆。 关于G-堆栈,在这里我们建议:如果不采用典型解决方案,就不要迁移G-堆栈存储器。如果你不确定数据是否在G-堆栈,那么可以用谓词memory:toPersistentStorage来获得一个副本,以确保不处于G-堆栈之中。,2004.11.3,AI程序设计课件,28,15.5.2 垃圾收集和全局堆栈,应该注意到,垃圾收集箱是一种循环回收机制:当某块内存不再需要时,不应该立即回收,而要看一看在外部代码中是否还要访问它。通常这都会自动处理,不存在什么问题。但是垃圾收集箱不知道(也不必知道)数据在外部
21、代码中何时存在。因此数据在Visual Prolog程序中存在的时间要长于在外部代码中存在的时间。 一种典型的保留内存的方法是将它插入事实段,然后在外部代码不再需要它时回收它。,2004.11.3,AI程序设计课件,29,15.6 Win32 API函数,也许你的程序从来不会调用其它编程语言的代码,因此你会认为学习这一部分没有必要。但要知道整个操作系统对于你的程序来说都是外部的,因此学习Win32 API很有必要。 操作系统提供成千上万有趣的外部例程,你可以利用本章的原则来调用它们。这些例程称为Microsoft Windows XXX API函数。不同平台提供的API有所不同,例如Windo
22、ws XP比NT 4.0提供更多的例程。 各平台API的在线文档可参见MSDN库。,2004.11.3,AI程序设计课件,30,15.6 Win32 API函数,从Prolog的观点来看,这个文档有一个问题:它用到许多字符常量,但却没有定义这些常量的值。例如,例程PlaySound的文档告诉我们可以用标志参数SND_ASYNC在程序中异步播放声音(即在应用程序继续执行期间播放声音)。SNC_ASYNC实际上是一个常数,但文档中并没有说明这个常数的值。 从平台SDK更新处下载SDK C/C+,在其中的*.h头文件中可以找到这些常量的宏定义。,2004.11.3,AI程序设计课件,31,15.6
23、Win32 API函数,至此,你应该能编写类似下面的代码了: implement playSoundFile open core resolve playSound externally domains soundFlag = unsigned32. class predicates playSound : (string Sound, pointer HModule, soundFlag SoundFlag) - booleanInt Success language apicall. constants snd_sync : soundFlag = 0 x0000. /* play syn
24、chronously (default) */ snd_async : soundFlag = 0 x0001. /* play asynchronously */ snd_nodefault : soundFlag = 0 x0002.,2004.11.3,AI程序设计课件,32,15.6 Win32 API函数,/* silence (!default) if sound not found */ snd_memory : soundFlag = 0 x0004. /* Sound points to a memory file */ snd_loop : soundFlag = 0 x0
25、008. /* loop the sound until next sndplaysound */ snd_nostop : soundFlag = 0 x0010. /* dont stop any currently playing sound */ snd_nowait : soundFlag = 0 x00002000. /* dont wait if the driver is busy */ snd_alias : soundFlag = 0 x00010000. /* name is a registry alias */ snd_alias_id : soundFlag = 0 x00110000. /* alias is a predefined id */ snd_ : soundFlag = 0 x00020000. /* name is */ sn
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 自行车与城市图书馆推广考核试卷
- 上海市徐汇、金山、松江区2024-2025学年高三摸底联考英语试题试卷含解析
- 网络安全技术实践教程(微课版)-教案 Windows平台安全强化
- 山东省滨州市滨城区北城英才学校等五校2025年数学三下期末学业水平测试试题含解析
- 山西青年职业学院《心电图学》2023-2024学年第二学期期末试卷
- 吉林省白山长白县联考2025年初三下-期中考试生物试题试卷含解析
- 辽宁省沈阳市第120中学2025届高三下学期模拟考试(一)化学试题含解析
- 辽宁科技大学《文化与创新制造之路》2023-2024学年第二学期期末试卷
- 江苏省苏州市草桥实验中学2024-2025学年初三下学期第三次模拟考试(5月)英语试题含答案
- 江西省赣州市兴国县达标名校2024-2025学年初三3月份月考试卷语文试题含解析
- T-CSTM 00290-2022 超高性能混凝土检查井盖
- 业务转让合同协议
- 2025年杭州市高三语文二模作文题目“科技与相互理解”写作指导
- 第四届“魅力之光”知识竞赛初赛题库
- 《旅行社经营与管理》电子教案 5-3 旅行社接待业务3
- 2025年浙江路桥中国日用品商城股份有限公司招聘笔试参考题库附带答案详解
- 2025年三力测试题模板及答案
- 餐饮行业企业战略管理论文4000字范文
- 第37届(2020年)全国中学生物理竞赛预赛试题及参考解答
- 老年康体指导-职业教育-1740155892240
- 急救与心理技能(视频课)知到智慧树章节测试课后答案2024年秋中南大学
评论
0/150
提交评论