Perl和C、C++等语言通信的编程方法

转:Perl和C、C++等语言通信的编程方法

强强联合——Perl 外部程序语言子程序与类的编程 
Author:天水-S.Tanshuai Email: 
OICQ: 66552 ICQ: 25856530 URL: Http://Www.Tanshuai.Net Location: FS, LN, P.R.C 
Date: 2001-5-19 20:07 Edition: Manuscript Version: 1.0 Current Language: Simplified Chinese

简介 
安装 
程序设计语言方法实现: 

C++ 
Java 
Python 
其它语言 
联合使用 
另一种方式——CPR 
结语

简介 
  我们知道Perl是目前最古老最强大的脚本程序语言,它的特点显而易见,就是快速开发应用和拥有广域的扩展性。Perl是一门高级,它和Java、Python一样在处理某些特殊任务的时候,仍显得力不从心,需要C/C++这些底层语言的支持,这就出现了扩展功能,例如Perl需要XS,Java需要JNI。然而实现这些方法并非易事。首先每一种扩展都会有它的特性,有它的不同,必须按照扩展对象的规定进行相应编写。如果你写了一个扩展程序,那么如果要用在Perl和Java上,你就要分别去写不同的接口。因此出现了很多更好的解决方案,这些不仅仅是对程序语言的扩展,我们知道,每一种程序语言都有它们的优点与其弱点。然而常常又因为开发周期和成本而无法用一种语言进行解决,因为这样很浪费时间。同时,不是每个人都对同一语言都是那么了解,每个人有自己擅长的程序语言。在Win32系统上,有ActiveX控件,和COM的实现方法,来解决这样的问题。然而这些仍然不是那么完善,Perl在Win32做控件,也是一种可行的方式。然而在Unix-Base系统上如何呢?而且控件仍然有其局限。 
  我想很多程序员也有和我同样的想法,如果流行的(当然所有的更好)程序语言都能够在一种环境下进行完美的编写那么该多好啊?但是这个想法在Perl语言中实现起来并不难。 
  另外我想说,本文除了对Perl程序员有很大的帮助之外,也绝对适合C、Java和Python程序员。因为不论在控制结构和函数调用方面都非常相似,甚至是一样的。这些程序员最多用一天就可以了解Perl的基本编写方法。如果你正在为多语言联合编程犯愁,那么用这个方法也不失为一种解决方案。 
//C Programming 
#include <stdio.h> 
main (){ 
char *str = "C 语言\n" 
printf("%s",str); 
}

//Java Programming 
class Hello { 
public void static main(String argvs[]) { 
String Str = " Java 语言\n"; 
System.out.print(str); 

}

#Python Programming 
String = "Python 语言\n" 
print String

//Perl Programming Perl6开始支持该种注释方法 
$String = "Perl 语言\n"; 
print $String 
// 
  这样,感觉起来有些不可思议,但是的确可以做到,这里面都是实现的方法(void模式),但是我们一般编程都需要函数见的数值传递,这里虽然没有体现到但是仍然可以做到。 
  Perl强大的嵌入功能,在这个应用上又一次体选出来了。Perl嵌入HTML 编程已经不是什么新鲜事务,我们也可以PerlDoc和Perl.COM的文章中找到如何把Perl嵌入在C中(利用Perl API),已经如何把C嵌入在Perl 里面(PerlXS),以及Perl发布代码中也包括如何把Perl嵌入在Java代码中(JPL),用Perl的语法调用Java对象等。但是这些方法非常复杂,兼容能力也很差,有一定的特性,所以利用起来也不是那么顺手。

安装 
  Perl这一外部程序语言子程序编程的功能也是最近才发布,所以Perl本身的版本是没有附带的,需要到CPAN下载该功能模块。这个模块叫做"Inline"。可以在任何操作系统平台上应用。 
  你需要有一个Perl5的解析器,当然最好是最新版本的Perl5.6.1 Stable。然后下载核心模块Inline,继而根据需求不同的程序语言来下载相应的子模块。目前Inline支持汇编(ASM)、C、C++、Java、Python、TCL程序语言,其中还包括一个CPR的Perl嵌入C的特殊实现模式。 
下载地址: 
核心模块(默认包含C的嵌入功能):http://www.cpan.org/authors/id/I/IN/INGY/Inline-0.34.tar.gz 
子模块 
汇编语言(ASM):http://www.cpan.org/authors/id/N/NE/NEILW/Inline-ASM-0.02.tar.gz 
C++语言:http://www.cpan.org/authors/id/N/NE/NEILW/Inline-CPP-0.20.tar.gz 
Java语言:http://www.cpan.org/authors/id/P/PA/PATL/Inline-Java-0.21.tar.gz 
Python语言:http://www.cpan.org/authors/id/N/NE/NEILW/Inline-Python-0.14.tar.gz 
TCL语言:http://www.cpan.org/authors/id/R/RR/RRS/Inline-Tcl-0.08.tar.gz 
CPR功能:http://www.cpan.org/authors/id/I/IN/INGY/Inline-CPR-0.11.tar.gz

  另外,你必须保证每个语言的编译器或解析器的存在。例如,你想要使用C/C++嵌入,你必须保证你拥有C++编译器,Win32是CL(VC),Unix是CC或者GCC;Java当然需要JDK;Python需要Python解析器。而且你也要保证需求模块、类、库等调用对象的存在,例如C的函数库,Java的类库,Python的模块等。

  下载相应模块后,进行编译安装,你必须拥有一个C语言的编译器,如果是ActivePerl,可以利用PPM。首先安装的是核心模块。所有的Perl模块的安装流程都是一样的: 
perl Makefile.PL<Win32/Unix> 
这个时候一般自动完成,并结束,但是有时候需要你输入一些量,例如安装目录等,核心模块是会问你是否默认安装C嵌入功能。 
nmake <Win32> make<Unix> 
进行编译,如果没有PerlXS,直接建立目的文件的目录结构。 
nmake test<Win32> make test<unix> 
这个步骤一般不需要做,但是如果你希望检查是否编译正确。 
nmake install<Win32> make install<unix> 
进行安装,把编译好的和建立的目录结构一同复制于目的目录中。

程序设计语言方法实现 
  一切安装配置就需有,就可以正式进行多语言编程了。本文选择几种常用语言进行讲解,其它语言读者可根据需求,阅读相应文档,也可以直接咨询与我。

C语言: 
  把C语言直接写入Perl代码中,轻而易举,我们知道在源代码中如果想把一个数据写入变量,是需要遵循一定的规则,例如: 
char *t = "XXX";是正确的,然而,我们平时写程序的时候,变量内容不一定是这样的,例如Web编程时,就需要使用HTML,那么实现起来 是非常费力的,我们需要在遇到“"”的时候,添加控制符号“\”,即使在Java 也没有充分解决这个问题,然而Perl就不需要。因为Perl的字符处 理功能实在是太强大了。 
  简单的实现: 
#!perl 
greet('天水');#是Perl语言。 
greet('Sam Tanshuai'); 
use Inline C => <<'END_OF_C_CODE'; 
#include <stdio.h> 
void greet(char* name) { 
printf(您好: %s!\n", name); 
}    
END_OF_C_CODE 
        输出结果是: 
        D:\Documents\Tests\Perl>perl InC.pl 
您好: 天水! 
您好: Sam Tanshuai! 
       ============================ 
  我们注意到,C代码是在调用语句的后面,按照一般的编写原理,这样是不可以的,但是use是在使用的时候是最高优先级,所以 use所属语句具有优先执行的能力,否则的话,必定出错。你发现了,在Perl里面的调用方法,不需要什么改动哦。这也就是我们为什么说“ Perl 外部程序语言子程序编程”,而不是多语言联合编程。它就是把一种语言当作自己的子程序去执行。 
  上面我们介绍的是向C语言子程序传递函数,进行操作,如果需要C语言返回函数,该如何去做呢?方法很简单: 
#!perl 
$add = add(1, 1); 
$subtract = subtract(9, 100); 
print "一加一等于:$add\n"; 
print "九减去一百等于:$subtract\n";

use Inline C => <<'END_OF_C_CODE'; 
#include <stdio.h> 
    int add(int x, int y) { 
       return x + y; 
        } 
    int subtract(int x, int y) { 
             return x - y; 
    } 
END_OF_C_CODE 
输出结果是: 
D:\Documents\Tests\Perl>perl InC.pl 
一加一等于:2 
九减去一百等于:-91 
============================= 
  至此程序编写的void方式和return方式都已经告知大家了,C可以使用指针,但是Perl不能引用C的指针,所以这是一个“遗憾”,因为如果 实现这种方法是存在难度的。 
  环境定义配置: 
  我们知道在编译C 的时候需要各种参数,例如INC和Lib的位置。因为嵌入编程,是外部调用的方式,这种方式类似于JSP,是编译后调用 。一般情况,直接perl就可以,但是有些时候考虑到移植等特殊问题,就需要稍微改动,这些功能可以在Perl初始化Inline的时候完成。 
AUTO_INCLUDE : 自动使用 include功能,代替在C语言中使用的#include语句 
use C => Config => AUTO_INCLUDE => '#include "yourheader.h"'; 
CC :你希望使用哪一个C语言编译器,一般情况下,它会使用编译Perl时候的编译器,如果你的系统有多个编译器,希望指定,可 以使用该方法。 
INC: 也就是 C 头文件的搜索路径。 
use C => Config => INC => '-I/inc/path'; 
LIBS: 库文件搜索路径。 
use C => Config => LIBS => '-lyourlib'; 
TYPEMAPS :指定使用额外的typemape文件 
use C => Config => TYPEMAPS => '/your/path/typemap'; 
  目前在Perl Inline-C的模式中支持一下数据类型: 
- int 
- long 
- double 
- char* 
- void 
- SV* Perl的API数组

C++: 
  这里的C++和C没有太大的差异。只是要在编译的时候进行具体分析: 
use Inline CPP => <<'END'; 
int doodle() { } 
class Foo { 
public: 
Foo(); 
~Foo(); 
int get_data() { return data; } 
void set_data(int a) { data = a; } 
private: 
int data; 
}; 
Foo::Foo() { cout << "创建Foo()" << endl; } 
Foo::~Foo() { cout << "删除 Foo()" << endl; } 
END 
  在这里涉及到了面向对象的程序设计的方法,所以需要特别注意。 
#!perl 
use Inline CPP; 
my $q = new Queue;#创建对象 Queue,这个对象是C++的。 
$q->q(50);#访问对象Queue的q函数,并传送整数"50"。 
$q->q("我是谁?");#访问对象Queue的q函数,并传送字符串。 
$q->q("我就是我。"); 
print "一共有", $q->size, "查询项目。\n"; 
while($q->size) { 
     print "关于: ", $q->peek, "\n"; 
     print "实际: ", $q->dq, "\n"; 
}

my $s = new Stack; 
$s->push(42); 
$s->push("什么?"); 
print "一共有 ", $s->size, "查询项目。\n"; 
while($s->size) { 
     print "关于 :    ", $s->peek, "\n"; 
     print "实际: ", $s->pop, "\n"; 
}


__END__ 
__CPP__


class Queue { 
   public: 
     Queue(int sz=0) { q = newAV(); if (sz) av_extend(q, sz-1); } 
     ~Queue() { av_undef(q); } 
     int size() {return av_len(q) + 1; } 
     int q(SV *item) { av_push(q, SvREFCNT_inc(item)); return av_len(q)+1; } 
     SV *dq() { return av_shift(q); } 
     SV *peek() { return size() ? SvREFCNT_inc(*av_fetch(q,0,0)): &PL_sv_undef;} 
   private: 
     AV *q; 
   };

   class Stack { 
   public: 
     Stack(int sz=0) { s = newAV(); if (sz) av_extend(s, sz-1); } 
     ~Stack() { av_undef(s); } 
     int size() { return av_len(s) + 1; } 
     int push(SV *i) { av_push(s, SvREFCNT_inc(i)); return av_len(s)+1; } 
     SV *pop() { return av_pop(s); } 
     SV *peek() { return size() ? SvREFCNT_inc(*av_fetch(s,size()-1,0)) : &PL_sv_undef; } 
    private: 
     AV *s; 
}; 
  在这里我们不难发现,Perl调用C++ 的对象和调用Perl的对象是一样的,是不是感觉还顺手呢?不知道什么时候也可以在其它程序语言中 这样做。

Java: 
  我除了喜欢Perl之外,其次就是Java啦。Java的确很不错,但是在编程的速度上,的确不如Perl,Java可以用好多不同的方法,实现一个功 能,的确很灵活,但是也非常麻烦。我用Java读一个文件的所有内容赋值到一个变量上,都搞了半天。 
  Java也是一个面向对象的程序设计语言,所以我们又要涉及对象概念了,我们按照上面C的例子,用Java来实现: 
#!perl 
my $java = new java();#创建新的对象 
$add = $java->add(1, 1);#返回输出数据计算结果 
$subtract = $java->subtract(9, 100);#返回输出数据计算结果 

$java->prt("一加一等于:$add");#利用Java函数进行输出 
$java->prt("九减去一百等于:$subtract");#利用Java函数进行输出

use Inline Java => <<'END_OF_JAVA_CODE'; 
class java { 
public java(){ 

public int add(int i, int j){ 
return i + j ; 

public int subtract(int i, int j){ 
return i - j ; 

public void prt(String s){ 
System.out.println(s); 


END_OF_JAVA_CODE 
  方法,我们知道创建一个对象的时候后,可以向该对象发送初始化的信息。在Perl中: 
#!perl 
use XXX; 
$ooXX = new XXX (Name=>xxx, Value=>0000); 
$ooXX->do(); 
        在Java中也可以实现这种方式,调用方法也是一样的: 
use Inline Java => <<'END'; 
class javaMethod { 
public Foo() { 
... 

public Foo2(int i, String str, Foo k) { 
... 


END 
my $obj = new Foo() ; 
my $obj2 = new Foo2(001, "String", $obj) ; 
  环境定义配置: 
    Java也需要进行相应的配置,当然一般的默认情况下,都可以完成的。 
BIN:设置Java二进制执行文件目录路径,放置java解析器和javac编译器文件的位置。 
CLASSPATH:设置Java类的所在位置,一般情况通过系统环境变量也可以完成。 
一个例子:  
use Inline { 
Java => 'DATA', 
       BIN => '/usr/jdk1.3/bin/', 
       CLASSPATH=>'/yourhome/path/;anyjarfile'; 
    ) ;


Python: 
  Python是一个很好的脚本程序语言,它的语法非常简洁,就好像写一篇文章一样,类似本文,但是也因此,有的时候程序总是出现莫名 其妙的错误,原来只是因为一个制表符 TAB。4月1日愚人节那天,Perl.com和Python.org发布了一条新闻,声称Perl和Python语言进行合并, 并且取名为"Parrot",但是我都被骗了。 
  不过即使没有"Parrot",Perl也可以完全适用Python。 
  按照上面的程序继续下来,我们来些Python版本的加加减减: 
#!perl 
$add = add(1, 1); 
$subtract = subtract(9, 100); 
print "一加一等于:$add\n"; 
print "九减去一百等于:$subtract\n"; 
    use Inline Python => <<'END_OF_PYTHON_CODE'; 
def add(x,y): 
return x + y 
def subtract(x,y): 
return x - y 
END_OF_PYTHON_CODE 
  方法和C是一样的,但是Python也涉及面向对象的程序设计。这里使用Data::Dumper模块来输出数据结构。 
#!perl 
use Inline Python => <<'END'; 
class Foo: 
def __init__(self): 
print "new Foo object being created" 
self.data = {} 
def get_data(self): return self.data 
def set_data(self,dat): 
self.data = dat 
END 
use Data::Dumper; 
my $obj = new Foo; 
print Dumper $obj; 
print Dumper $obj->get_data(); 
    $obj->set_data({string => 'hello', 
                    number => 0102, 
                    array => [1, 2, 3], 
                   }); 
    print Dumper $obj->get_data();                   
  输出结果为: 
             D:\Documents\Tests\Perl>perl Python.pl 
             $VAR1 = bless( do{\(my $o = 135870536)}, 'main::Foo' ); 
             $VAR1 = {}; 
             $VAR1 = { 
                             'string' => 'hello', 
              'array' => [ 
                           '1', 
                           '2', 
                           '3' 
                         ], 
              'number' => '102' 
                      }; 
                     ========================================== 
                      Eval: 
                        因为Python和Perl一样是一个很纯脚本语言,所以它们都支持eval功能,这是一个很强大的功能,在perl中也可以直接使用python的           eval来完成相应功能。 
                        方法如下: 
                        $SC = "print 'hello'"; 
                              eval_python("$SC") 
                              eval_python("<perl 包>", "<python 函数>", <参数>...) 
    eval_python("<perl 包>", "<python 方法>", <对象>, <参数>...) 
    实现例程: 
    use Inline::Python qw(eval_python); 
    eval_python("def test(): return {'第一': 1, '第二': 2}"); # 返回一行内容 
    eval_python("test()"); #返回整数 1。 
  Python的功能越来越强大,也受到商业的支持,如果你在Perl编程方面已经有很好的造诣,那么学习Python决非难事,一般情况下两三天  之内就可以掌握。 
其它语言: 
  因为我目前擅长的语言中,只有C、Java、Perl和Python,所以其它语言在此就不详细见解,例如:汇编、TCL等并不流行,再此我将讲 解Inline模块的通用使用方法,大家再根据以上例子进行对照,就很容易掌握。 
  下载相应的语言子模块,使用Inline进行调用: 
use Inline <语言名称> 
例如:use Inline C;#C语言 
            use Inline CPP;#C++语言 
            use Inline Java;#Java语言 
            ..... 
程序结构: 
标准结构: 
use Inline <语言名称> => <<'END_OF_XXX_CODE'; 
<相应程序代码主体> 
END_OF_XXX_CODE 
简明结构: 
use Inline <语言名称>; 
     <Perl调用代码主体> 
__END__ 
     __ <语言名称>__ 
     <相应程序代码主体> 
     复合规范: 
     use Inline C; 
     use Inline Java; 
     use Inline Python; 
     <Perl应用代码主体> 
     __C__ 
     <C 语言代码主体> 
     __C__ 
     <第二个 C语言代码主体> 
     __JAVA__ 
     <Java语言代码主体> 
     __Python__ 
     <Python语言代码主体> 
     
  使用选项: 
    我们在使用其它程序语言的时候,需要对编译、解析等方法进行定制,这里介绍如何定制某个语言的选项。 
C选项的例子: 
   use Inline (C => Config => 
   DIRECTORY => './inline_dir', 
                 LIBS => '-lfoo', 
                 INC => '-I/foo/include', 
                 PREFIX => 'XXX_', 
                 NOWARN => 1, 
                ); 
     use Inline C => <<'END_OF_C_CODE';

联合应用 
  我们把话题转回最初的设想,把Perl、C、Java、Python这四个语言,写在一个程序内。 
#!perl 
use Inline C; 
use Inline Java; 
use Inline Python;

#Perl Programming Perl6开始支持该种注释方法 
$String = "Perl 语言\n"; 
print $String 
#

__C__ 
//C Programming 
#include <stdio.h> 
main (){ 
char *str = "C 语言\n" 
printf("%s",str); 
}

__JAVA__ 
//Java Programming 
class Hello { 
public void static main(String argvs[]) { 
String Str = " Java 语言\n"; 
System.out.print(str); 

}

__Python__ 
#Python Programming 
String = "Pthyon 语言\n" 
print String 
输出结果为: 
Perl 语言 
C 语言 
Java 语言 
Python 语言

  这是一个简单的联合例子,让我们在复杂一些,用这四种语言做不同分工,由C语言计算加法,Java语言计算减法,Python语言计算乘法 ,最有由Perl进行除法后输出。

#!perl 
use Inline C; 
use Inline Java; 
use Inline Python; 
my $java = new subtract(); 
my $C = add(5,6); 
my $J = $java->do($C,3); 
my $P = x($J,10); 
my $R = $P/3; 
print "最终结果: $R\n";

__C__ 
//C Programming 
#include <stdio.h> 
int add (int x,int y){ 
return x+y; 
}

__JAVA__ 
//Java Programming 
class subtract { 
public int do(int x,int y) { 
return x-y; 

}

__Python__ 
#Python Programming 
def x(x,y): 
       return x * y 
输出结果为: 
最终结果:26.6666666666667 
==============================

另一种方式——简单的Perl嵌入C 
   CPR(C Perl Run)是另一种的功能,是把Perl代码放入C中,不同的是这个C是不能成为正式的编译的C。而是一种Script脚本模式。但是它仍然比利用API方法嵌入的C方便得多,在这里是一个eval函数功能。 
  方法如下: 
      int main(void) {        
         printf("Hello World, I'm running under Perl version %s\n", 
                CPR_eval("use Config; $Config{version}") 
               ); //CPR_eval就是使用了Perl的语言方式。 
         return 0; 
     }

  它和Perl Inline的标准模式不一样,不使用Perl进行解析,而是输入cpr xxx.cpr就可以运行。但是该程序不支持Win32系统平台。 
  目前CPR只能在以下函数原型运行: 
int main(void); 
  不可以在以下方式运行: 
int main(int argc, char* argv[]); 
   
结语 
  C语言是采用API动态加载模式运行的,即启动Perl解析器后自动加载API扩展。开始我以为是启动了另一个进程做线程通讯,但是我通过Windows“任务管理器”查看进程的时候,只有一个Perl,说明Perl在处理嵌入式多语言方面的能力的确强大。
  正是因为Perl有用强大的字符串处理能力,才可以让不同格式代码写入在一个程序中。之前我们一般使用COM CORBA这些技术来进行不同程序语言的通讯,它们有它们的好处。但是作为一个小型应用开发,是不可能启动一两个服务器端进行调用,而且仍然要涉及到平台移植的问题。 
  Perl强大的功能,将会是您提高开发效率的有力工具。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值