yy使用C语言为Python编写纠错码模块
c语言吧
全部回复
仅看楼主
level 1
狂野灰狼 楼主
不累的王
普通会员
发贴: 339
积分: 0
来自:
注册日期: 2006-05-26
   发表时间: 2008-04-10 02:26:40  
--------------------------------------------------------------------------------
yy使用C语言为Python编写纠错码模块
去年一个项目的开发中因为需要使用到纠错码,所以自然而然的接触到了rscode。
rscode 是Reed-Solomon纠错算法的一种实现,被广泛的使用于Audio CD和CD-ROM。关于rscode更详细
的描述,请前往其官方网站查看(http://rscode.sourceforge.net/)。
rscode 使用标准C编写,优点自不必说,跨平台、执行效率高。可C代码也有其固有的麻烦,每次调试都
需要编译,开发过程远不如脚本语言来得阳春白雪。于是乎,笔者生出一个想法:何不将其编译为Python模
块?这样在测试程序逻辑的时候可以省去不少的麻烦。现在将过程记录如下,希望对大家有所帮助。
首先在官方网站下载源文件。
解压源代码,并将其编译为静态链接库。
项目的环境为Win32,不过因为笔者的拧巴性格,还是使用了MingGW系列的工具对其进行编译。
执行make,得到静态链接库:
libecc.a
接下来开始为我们的模块编写C源码。
         /*
          *         RsCode.c
          */
         #include <python.h>
         #include "ecc.h"
         //编码部分
         //包裹函数调用的实际编码函数
         //参数依次为:原文buffer指针,buffer长度,得到的rscode编码串的指针
         void _encode(char* data, unsigned long size, char* codeword)
         {
                 //调用rscode库提供的两个函数,分别完成初始化和编码工作。
                 initialize_ecc();
                 encode_data(data, size, codeword);
         }
         //编码部分的包裹函数,这个函数将和CPython的虚拟机进行亲密接触 :)
         //函数参数的定义。self为当前模块的引用;args为传入这个函数的参数,可以是任意数据类型。当
然,如果传入参数与处理过程不匹配的话,就会产生一个异常。
         PyObject* wrap_encode(PyObject* self, PyObject*   args)
         {
                 char*         data;

2010年03月22日 06点03分 1
level 1
狂野灰狼 楼主
                 int          data_size;
                 char         codeword[256];
                 PyObject* resString;//储存编码结果的Python字符串对象。
                
                 //使用Python/C API中Tuple对象的方法,得到指定顺序的参数。
                 //在这个函数中,我们将参数视为一个列表,其中第一个元素为数据的引用,第二个元素为数据
长度。
                 data = PyString_AsString(PyTuple_GetItem(args, 0));
                 data_size = PyInt_AsLong(PyTuple_GetItem(args, 1));
                 //调用前面定义的编码函数,将结果存入codeword中。
                 _encode(data, data_size, codeword);
                 //构造Python中的Buffer对象。
                 //PyString_FromStringAndSize这个函数是笔者从Python/C API的几角旮旯中找到的,它将严格
按照输入数据的指针和长度构造PythonBuffer对象,而不会像一般的PythonString对象构造API一样遇到“\n”就
结束了。这函数恐怕是大家最需要的了,呵呵。
                 resString = PyString_FromStringAndSize(codeword, data_size + NPAR);
                
                 //OK这个函数最终将返回生成的Python Buffer对象。
                 return resString;
         }
        
         //解码部分
         //格式方面照猫画虎即可,解码时调用的rscode库中的方法,参照了rscode自带的例子。
         void _decode(char* data, unsigned long data_size)
         {
                 initialize_ecc();

2010年03月22日 06点03分 2
level 1
狂野灰狼 楼主
                 decode_data(data, data_size);
                 correct_errors_erasures(data, data_size, 0, 0);
         }
         //同样需要编写一个返回Python数据类型的包裹函数。
         PyObject* wrap_decode(PyObject* self, PyObject* args)
         {
                 char*         data;
                 int         data_size;
        
                 PyObject* resString;
                 data = PyString_AsString(PyTuple_GetItem(args, 0));
                 data_size = PyInt_AsLong(PyTuple_GetItem(args, 1));
                 _decode(data, data_size);
                 resString = PyString_FromStringAndSize(data, data_size);
                 return resString;
         }
         //定义这个模块所包含的方法,格式如下的
         static PyMethodDef         RsCodeMethods[] =
         {
                 //分别声明方法在Python中的名字,实际执行中调用的C包裹函数名,以及Python函数说明文
档。
                 {"encode", wrap_encode, METH_VARARGS,
                  "encode(str, str_size)\n     decode data with rscode.\nlen(data) + NPAR < 256\n"
                 },
                 {"decode", wrap_decode, METH_VARARGS,
                  "decode(codeword, codeword_size)\n     decode data with rscode.\n"

2010年03月22日 06点03分 3
level 1
狂野灰狼 楼主
                 },
                 //以两个NULL作为声明的结束。
                 {NULL, NULL}
         };
         //模块在被引用时,将调用的初始化函数。作用是向虚拟机注册模块中的对象。注意函数名称的格式。
         void initRsCode()
         {
                 PyObject*         m;
                
                 m = Py_InitModule("RsCode", RsCodeMethods);
         }
         /*
          *         End Of RsCode.c
          */
下面完成RsCode.c的编译。
         #
         #         Makefile for RsCode.pyd
         #
         # ecc.h 所在的目录。
         RSHEAD_FLAG = -I"d:\ts\sm\rscode-1.0"          
         # libecc.a 路径。
         RS_LIB = d:\ts\sm\rscode-1.0\libecc.a        
         # Python头文件所在位置
         PYHEAD_FLAG = -I"C:\Python24\include"        
         # Python虚拟机静态库路径
         PY_LIB = c:\Python24\libs\li
bp
ython24.a         #
         # 我们的目标文件
         TARGETS = RsCode.pyd
         all:
                 gcc $(RSHEAD_FLAG) $(RS_LI $(PYHEAD_FLAG) $(PY_LI -shared -o $(TARGETS)
         # End of Makefile
         从Makefile不难看出,我们编译后得到的模块RsCode.pyd其实是一个动态链接库。

2010年03月22日 06点03分 4
1