程序连接方法

文档序号:6554951阅读:729来源:国知局
专利名称:程序连接方法
技术领域
本发明涉及不同编程语言的连接,尤其是从面向对象的编程语言中调用面向函数的编程语言的子程序,或者相反。
已知有许多编程系统可以被用来编制数据处理设备的程序。另外,下文采用编程语言JAVA和C作为例子。产生程序代码的翻译程序属于编程语言的抽象说明。因此该翻译程序是被计算机安装用于某个行为的工具。
随着新编程语言-此处为JAVA-的引入,便提出了调用另一编程语言的子程序的问题。通常已知以下技术,即一旦所述的编程语言足够地相似,便由该技术翻译不同编程语言-实现的调用协定。譬如已知有混合地使用C和Pascal,其中大多由一个关键字来相应地表征所述的函数或过程。只要它涉及简单的变量,则该技术是简单和已知的。在共同地使用一些结构时会产生更大的问题。此处的解决方案大多是,可以在存储器内进行共同的表示,或在知道存储器结构之后人工地编制一对表示相同存储器结构的描述。
但在连接面向对象的语言(如JAVA)和面向函数的语言(如C)的情况下,当涉及结构时尤其会产生问题。因为JAVA不知道C的结构;最佳的近似在于使用一些必要时被嵌套的对象。
在JAVA中已设立一个接口来尤其调用C程序。该接口被称为“JAVA本机接口”,并简称为JNI。尤其可以在http//java.sun.com/docs/books/tutorial/native1.1/index.html下找到描述。其中着重指出,必须匹配C函数“在现实世界中”你也许拥有那些你想与Java程序综合起来的现有C函数,而你仍然需要修改这些C函数的标志以便利用JNI进行工作。因此,在没有为每个如此调用的函数编制一个通常被称为“打包函数”(wrapperfunction)的辅助函数的情况下,并不能毫无问题地从JAVA调用预定的C函数。尤其是需要分别单独地把C语言中的结构用法翻译成参数,因为在JAVA中不存在结构。
因此本发明的任务在于从JAVA中调用预定的C函数且该C函数的参数是预定的C结构,而无需为C函数和C结构单独地和人工地编制“打包函数”。
下面接着例子来讲述该任务的解决方案,该实施例在下文采用JAVA和C编程语言。程序的表示包括一行开始处的行号,该行号只被用作参考。
在此,该解决方案采用了被称为串行化的技术,且在http//java.sun.com/docs/books/tutotial/essential/io/serializing.html下进行了描述。在该解决方案中,每个类中都设有一个用于串行化的方法和一个用于相反方向的方法。所述的串行化方法通过“writeobject”来称呼,并被迭代地应用于一个类的所有元素。在此,所述的迭代采用了运行时间系统“JAVA虚拟机”,所述的运行时间系统便从需要串行化的对象中动态地、也即只有在运行时间内才求出需要处理的字段,当涉及基本类型、且一旦请求对象便迭代地处理这些基本类型时,便以标准的方式输出所述的字段。
下面借助一个简单的例子来讲述串行化,正如其在本发明中所应用的那样。作为基本元素,采用整数类型“Inter”和浮点数类型“Float”。两者被定义为类<pre listing-type="program-listing"><![CDATA[1class myInt {2 public Integer val=new Integer(0);3 public void show(String id) {4 System.out.println(id+".val="+val);5 }6 public String toX() {7 return"I"+val+";";8 }9 public String fromX(String buf) {10 int semi=buf.indexof(′;′);11 try {12 val=val.valueOf(buf.substring(1,semi));13 } catch(NumberFormatException e) {14 val=new Integer(0);15 }16 return buf.substring(semi+1);17 }18 }]]></pre>在第1行通过下面的程序文本定义类“myInt”。它在第2行包括类“Integer”中的一个存储器位置’val’。该应用中的每个类知道三种方法,即第三行的“show”、第六行的“toX”和第九行的“fromX”。“show”只被用于显示测试目的的值。
方法“toX”用于串行化。它以串返回标准形式的值,其中在指示符(此处为“I”)之后跟有一个十进制数字,该值通过一个分号结束。
方法“fromX”期待一个恰好以这种格式的元素开始的串,也就是说具有一个总是为“I”的指示符、所述十进制数字的值以及一个分号。后者的位置在第10行求出。在取出对象值和存放到“val”中之后,由“formX”返回所述字符串的其余部分。
因此所述的两个函数“toX”和“fromX”是互逆的;尤其由x.fromX(x.toX())促使通过“toX”读出所述的值,并通过“fromX”进行重新设置,其中x是类“myInt”的对象。
相应地定义类“myFloat”<pre listing-type="program-listing"><![CDATA[20class myFloat {21 public Float val=new Float(0.0);22 public void show(String id) {23 System.out.println(id+".val="+val);24 }25 public String toX(){26 return"F"+val+";";27 }28 public String fromX(String buf) {29int semi=buf.indexOf(′;′);30try {31val=val.valueOf(buf.substring(1,semi));32} catch(NumberFormatException e) {33val=new Float(0.0);34}35return buf.substring(semi+1);36}37}]]></pre>假定在C中存在一种简单的结构typedef struct MyStruc2 {int s2f1;};该结构被转换为下面的.JAVA类<pre listing-type="program-listing"><![CDATA[40class myStruc2 {41 public myInt s2f1=new myInt();42 public void show(String id) {43 s2f1.show(id+".s2f1");44 }45 public String toX() {46 return′{′+s2f1.toX()+′}′;47 }48 public String fromX(String buf) {49 String cpy=buf.substring(1);50 cpy=s2f1.fromX(buf);51return cpy.substring(1);52 }53}]]></pre>在第41行定义数据区s2f1;方法“show”用于显示该值。
方法“toX”以串的形式产生在圆括号内的值。“fromX”提供返回路径。两种方法也象方法“show”一样使用迭代的调用,以便为结构元素执行相应的函数。
现在利用这些元素用C语言构造一个稍微复杂的结构typedef struct myStruc1 {int s1f1;int s1f2[2];float s1f3;myStruc2 s1f4;}相应的等价体用JAVA表示为
<pre listing-type="program-listing"><![CDATA[56class myStruc1 {57 public myInt s1f1=new myInt();58 public myInt[] s1f2=new myInt[2];59 public myFloat s1f3=new myFloat();60 public myStruc2 s1f4=new myStruc2();61 public myStruc1() {62 for (int i=0;i<2;++i) {63 s1f2[i]=new myInt();64 }65 }66 public void show(String id) {67 s1f1.show(id+".s1f1");68for (inti=0;i<s1f2.length;++i){69s1f2[i].show(id+".s1f2");70}71 s1f3.show(id+".s1f3");72 s1f4.show(id+".s1f4");73 }74 public String toX() {75 String buf=s1f1.toX();76 buf+=′[′;77 for (int i=0;i<s1f2.length;++i) {78 buf+=s1f2[i].toX();79 }80 buf+=′]′;81 buf+=s1f3.toX();82 buf+=s1f4.toX();83 return′{′+buf+′}′;84 }85 public String fromX(String buf) {86 buf=buf.substring(1);87 buf=s1f1.fromX(buf);88 buf=buf.substring(1);89for (int i=0;i<s1f2.length;++i) {90buf=s1f2[i].fromX(buf);91}92 buf=buf.substring(1);93 buf=s1f3.fromX(buf);94 buf=s1f4.fromX(buf);95 return buf.substring(1);96 }97}]]></pre>对于该结构的每个字段,在方法“toX”和“fromX”中通过递归地调用该字段的相应方法变换成标准的线性表示,或从标准的线性表示变换而来。对于阵列“s1f2”,必须相应地通过所述的元素进行迭代,正如在第78和90行内所进行的一样。此处也用圆括号来标记该结构;所述的阵列被包含在方括号内。
另外还给该实施例设立了类“CallC”<pre listing-type="program-listing"><![CDATA[101 class CallC {102 public String execC(String func,String buf) {103 System.out.println("Calling"+func+";"+buf);104 int off=buf.indexOf("9876");105 String mod=buf.substring(0,off)106 + 6789107 + buf.substring(off+4);108 System.out.println("Modified"+mod);109 return mod;110 }111}]]></pre>该类只包含有方法“execC”,由该方法显示所述的自变量,并通过用“6789”代替数“9876”来修改所提供的字符串。该方法真正代表了用C函数的调用,这在稍后将详细讲述。
为了论证这种JAVA代码,还在类“sample”中定义一个主程序“main”<pre listing-type="program-listing"><![CDATA[113 public class sample {114 private static myStruc1 my1=new myStruc1();115 static void myInit() {116my1.s1f1.val=new Integer(1234);117my1.s1f4.s2f1.val=new Integer(9876);118my1.s1f2
.val=new Integer(11);119my1.s1f2[1].val=new Integer(12);120my1.s1f3.val=new Float(5.6);121 }122 public static void main(String[] params) {123System.out.println("begin...");124myInit();125my1.show("old my1");126String flat=my1.toX();127flat=new CallC().execC("aFunc",flat);128my1.fromX(flat);129my1.show("new my1");130System.out.println("done.") ;131}132 }]]></pre>
在此,在第115-121行中首先用举例值来赋值类“myStruc1”的对象“my1”。处于清晰的缘故,这里通过直接访问对象的字段来实现。在现实的应用中,需要采用与此相匹配的方法,但其表述是由该应用的内容制定的,因此在此没有意义。
在第124行中初始化在第114行中编制的对象。在第125行中显示值。在第126行中通过-递归地-在变量“flat”中调用“toX”而以标准的线性表示来产生对象。在第127行调用方法“execC”,该方法通常作为C函数经JNI进行调用,但此处利用JAVA类来进行仿真,并以线性化的标准形式返回一个必要时被更改的结构,其被保留在变量“flat”中。借助所述的串,此时通过-递归地-调用“fromX”把所述的可能被更改的值存放在所述的对象中。
可以看到,函数“toX”递归地构造所述的串,而“fromX”以相同的方式拆除它。
显然,可以通过一个程序自动地从相应的结构定义中生成所述的方法“fromX”和“toX”。对于每个元素,递归地调用各自的方法。在“toX”的情况下,其输出被附加到所述的串上;在“fromX”的情况下,其结果表示需进一步处理的其余部分。
如果把所有的程序行1-132集中成一个JAVA程序,再翻译和执行该程序,则出现以下输出begin...old my1.s1f1.val=1234old my1.s1f2.val=11old my1.s1f2.val=12old my1.s1f3.val=5.6old my1.s1f4.s2f1.val=9876Calling aFunc{I1234;[I11;I12;]F5.6;{I9876;}}Modified{I1234;[I11;I12;]F5.6;{I6789;}}new my1.s1f1.val=1234new my1.s1f2.val=11new my1.s1f2.val=12new my1.s1f3.val=5.6new my1.s1f4.s2f1.val=6789done.
可以明显看到遵照C结构“myStruc1”的对象“myStruc1”的结构,还有其值的标准表示“{I1234;[I11;I12;]F5.6;{I9876;}}”。
但至此为止尚未使用格式指示符“I”、“F”、“{”和“}”。此处的分号只是为清楚起见而插入的;也可以取消它。所述的串也可以有其它的表示。由于JAVA串是作为单一码利用每个字符为16比特而存储的,而且所述类“String”的方法不一定非常快,所以优化方案在于使用预先施加的字节-阵列,并用二进制数据填充该阵列。为替代十进制的数值表示,显然也可以采用16进制和36进制。就可移植性和可维护性的损失而言,这种优化是否值得,必须在每个单个情况下具体地通过测量来证实和判断。这种和类似的优化对本领域技术人员是公知的,因此下文不再详述。
利用至此所讲述的手段,此时可以实现通过方法“toX”可以线性地出现所以的数据区,利用方法“fromX”可以再次存放。因此,这些方法体现了已知的串行化函数的特殊特点,并且也可以替代其位置。
但与从JAVA所公知的串行化函数相反,首先确定由在本发明所使用的串行化函数产生一个确定的字段顺序,也即所述字段在所述结构内被定义时的顺序。另外,通过串行化,把该结构的格式按照函数语言C表示为非常简单的形式。相反,在JAVA内已有的串行化只存储用于对象的信息,但显然不包含关于所属C结构的结构信息。
此时,所述内容的这种线性化的且设有类型指示符的存储形式可以被转换成一种与各种C结构相对应的存储器布局,而与所述结构的定义无关。为此采用C语言来-优选也递归地-分析所述的字符串、求出和相应地处理所述的类型指示符。如果所述的类型指示符表征一个简单的变量,则转换接下来的数字,并按二进制存储在相应长度和对齐的存储区中。如果所述的类型指示符表征一个结构,那么,即便该结构仅由不需要对齐的字节组成,但在一些实现当中也经常需要对齐双字的边界。该处理对于C语言的相应编译系统是特有的,并且对应于从该编译结构中充分公开的技术,必要时由相应的编译器的源代码接管该技术。
打包函数可以如下<pre listing-type="program-listing"><![CDATA[901 void pack_stru(char*fmt,void*stru)902 {903int i,j;904for (i=0;i<strlen(fmt);) {905 switch fmt[i++] {906 case′I′stru=align(stru,4);907 sscanf(fmt,"%d;%n",(int*)stru,&amp;j);908 i+=j;stru+=4;909 break;910 case′F′stru=align(stru,8);911 sscanf(fmt,"%f;%n",(float*)stru,&amp;j);912 i+=j;stru+=8;913 break;914 case′{′stru=align(stru,8);915 break;916 case′}′stru=align(stru,8);917 break;918 case′]′919 break;920 case′[′921 break;922 }923}924 }]]></pre>函数“pack_stru”具有两个参数,一个指示符指示组合的格式及数据串,以及一个指示符指示一个(足够大的)存储区,在该存储区内建立所述的结构。所述的存储区与类型无关地被定义为“viod*”。此时,由第904-923行的循环处理所述组合的格式及数据串。由第906、910、914和916行的函数“align”执行地址到第二参数的倍数的对准,此处没有示出,因为它们较大地依赖于相应的计算机系统。在第907和911行,通过库函数“sscanf”从串“fmt”提取所述的值,并存储在用指示符“stru”定址的存储区中,其中由于形式的正确性而进行类型的匹配。处理的字符数量被输出,并被用于格式及数据串的串接。“阵列”指示符“[‘und’]”在此是不起作用的;这也取决于各种实现。
于是,正如用“CallC”类中的方法“execC”所表示的一样,提供需调用的C函数的名称和一个包含有随该C函数一起给出的结构编码的字符串。通过JNIC以C函数的形式调用方法“execC”,并象所示的那样把该字符串转换成与所述结构相应的存储器格式。于是,调用在第一参数内给出的C函数,并提供一个指示存储器结构的指示符。
作为该函数返回之后的结果,可以改变所述存储器结构的字段。由此,函数“execC”从该存储器结构再次产生标准的表示。为此使用所述被提供的、恰好描述了所述存储器结构的字符串,并对其进行重新处理。拷贝所述的类型指示符,并随后插入所述存储位置的值或代替现有的值。根据与其产生时相同的长度和对齐规则来实现存储器地址内的串接。如果以固定的(最大)长度存储所述的数值,则可以简单地进行重写。
于是,由函数“execC”返回了存储器结构值的线性化表示。随后利用方法“fromX”对该存储器结构再次进行递归的分析,并被用来更新所述对象内的字段值。
在至此为止的例子中,所述的类型指示符和所述的值是混合地被存储在相同的串内。显然也可以将两者分开地在两个串内产生。于是从{I1234;[I11;I12;]F5.6;{I9876;}}产生格式串{I [I I]F{ }}以及数据串1234;11;12;5.6;9876;这有个优点,即在函数或方法“execC”的方法内返回被调用的函数之后,只须借助所述被编码的结构描述{I [I I]F{ }}以新字符串的形式汇编所述结构元素的值,为此可以从头重写包含有所述输入值的缓冲器。另外在该情形下,也可以静态地提供所述的结构信息。当优选地象上述那样从C结构描述自动地产生串行化和去串行化方法“toX”和“fromX”时,便尤其是这种情况。数据串的编制由此变得更为有效。
所述的方法也可以用来从C函数调用JAVA方法。为此可以静态地提供所述的格式串,或者通过调用串行化方法ad hoc来进行编制。在后一种情况下,必须先对所需的对象进行实例化和初始化。此时借助格式串可以通过拆包函数把C结构转换成串行的形式。最迟必须在现在实例化和初始化所需的对象。在JNI中设立了为此所需的调用。同样,通过在JNI中所设立的手段首先调用与对象结构相应的对象的去串行化方法“fromX”,然后调用最后需要调用的任一对象的JAVA方法,该对象根本就与分配给所述结构的对象无关。在返回之后,通常是反向地、或者与在从JAVA调用C时的第一部分相应地运行相应的过程。
权利要求
1.从面向对象的编程语言(JAVA)中调用面向函数的编程语言(C)的函数的方法,在所述的面向函数的编程语言中,函数以参数的形式期望一种结构,而在面向对象的编程语言中,给字段分配与所述的结构相应的JAVA类,具有一些步骤-以格式串提供一个描述所述结构的字符串,-通过递归地调用一种串行化方法(toX)提取在所述结构中所使用的字段的内容,并且将其以一个与所述格式串相应的顺序存放在一个数据串中,-由一个打包函数利用所述的格式串把所述的数据串转换成所述结构的存储器映像,-利用所述的存储器映像以所述结构的参数形式调用所述面向函数的编程语言的函数。
2.按权利要求1的方法,具有以下进一步的步骤-由一个拆包函数利用所述的格式串把所述的存储器映像转换成一个数据串,-通过递归地调用一种去串行化方法(fromX),以一个与所述格式串相应的顺序从所述的数据串中提取在所述结构中所使用的字段,并将其存放在所述对象的字段中。
3.按权利要求1或2的方法,其中把所述的数据串和所述的格式串混合成一个借助串行化方法产生的公共串。
4.以面向函数的编程语言(C)的函数形式调用面向对象的编程语言(JAVA)的方法的方法,其中在调用所述的函数时以参数的形式提供一个结构,并且给字段分配与所述结构相应的JAVA类,具有以下步骤-产生与所述结构相应的、包括所需子对象的对象,-在一个格式串中提供一个描述所述结构的字符串,-由一个拆包函数利用所述的格式串把存储器映像转换成一个数据串,-通过递归地调用一种去串行化方法(fromX),以一个与所述格式串相应的顺序从所述的数据串中提取在所述结构中所使用的字段,并将其存放在所述对象的字段中,-调用所述的方法。
5.按权利要求4的方法,具有以下进一步的步骤-通过递归地调用一种串行化方法(toX)提取在所述结构中所使用的字段的内容,并且将其以一个与所述格式串相应的顺序存放在一个数据串中,-由一个打包函数利用所述的格式串在所述结构的存储器映像中替换掉由所述数据串中存在的值所组成的字段。
6.用于编制为执行上述方法所需的程序的方法,其中,从一种用面向函数的编程语言所描述的结构中至少产生串行化或去串行化方法的程序文本。
全文摘要
从面向对象的编程语言(譬如JAVA)中调用面向函数的编程语言(譬如C)的函数的方法,其中,通过递归地调用一种串行化方法(toX),把在结构中所使用的字段的内容以一个与所述格式串相应的顺序存放在一个数据串中,然后由一个打包函数把所述的数据串转换成所述结构的存储器映像,并利用所述的存储器映像以参数形式调用所述面向函数的编程语言的函数。
文档编号G06F9/46GK1447938SQ01814435
公开日2003年10月8日 申请日期2001年7月12日 优先权日2000年8月24日
发明者A·德雷塞尔豪斯, R·维格纳 申请人:温科尼克斯多夫国际有限公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1