python与c的集成

来源:互联网 发布:开淘宝用mac 编辑:程序博客网 时间:2024/05/20 11:51

记得在大学里和同学一起进行游戏开发,可到了后来完全无法继续下去,现在想想原因,一是自己的水平有限,另一个就是没做到游戏引擎与数据的分离,也就是没有理解脚本。那时的我根本就不知道什么叫做脚本编程,现在随着工作的深入也渐渐理解了一点。
虽然脚本语言有很多种,但是我毫不犹豫了选择了python,我觉得它真的是一个好东西,但是我用到的只是它最基本的东西,毕竟我只是用它来进行游戏方面的脚本编程。所以我最先关心的就是怎么将它与c集成,即可以与系统引擎进行交互。(主要参考图书《游戏脚本高级编程》)

1. 首先就是在编译器中把python安装目录include/与libs/加入,对于这点我在vc6中可以,但是在dev c++中即使加入了编译也会出错,说找不到python头文件,这点比较郁闷,不过考虑到一般windows编程都用的是vc,所以并没有什么影响吧!!!
然后用#include <Python.h>就可以把python的主头文件包含进来了。
但是在调试的时候,会出现说找不到python25_d.lib的链接错误,出现这个错误的原因是python_d.lib是库的调试后形式,当我们以debug模式编译工程时,python就用这个lib文件,但是这个文件是不可用的。对于这点,最快的办法就是强制要求python在任何情况下都是用非调试版本,就可以了。要做到这一点
a) 在python目录include文件夹下,打开pyconfig.h,找到如下语句
  ifdef _DEBUG
   pragma comment(lib,"python25_d.lib")
  else
   pragma comment(lib,"python25.lib")
  endif
将python25_d.lib改成python25.lib
b) 找到
#ifdef _DEBUG
define Py_DEBUG
#endif
将其用屏蔽
 这样就可以了。

2. Python初始化
python的初始化很简单我们只需在程序开始时调用Py_Initialize(),结束的时候调用Py_Finalize()就可以了

3. PyObject
在c语言程序中,我们使用PyObject来操纵python对象,一个PyObejct就是一个结构体,他表示某个与python相关的数据。只不过我们处理的都是该对象的指针。
PyObject *t;  //t is a pointer to the python object

4. Reference counting
对于python,跟directx比较类似,都采用了一种引用计数的机制,我们不需要自己去释放python对象,只需减少它的引用计数就可以了,当计数为0时,系统自己会安全释放。
对于减少引用计数,我们使用Py_XDECREF(),而增加引用计数则是由代码负责完成。

5. 载入脚本
我们首先写一个python脚本,命名为test.py

printf “Hello World”
 然后我们在主程序中调用,如下
  PyObject *pName = PyString_FromString("test");
        PyObject * pModule = PyImport_Import(pName);
   
     if(!pModule)
     {
         printf("could not open script \n");
         return 0;           
     }
 这样就可以在控制台上面看见Hello World了。

6. 调用脚本定义函数
我们在test.py中定义一个函数,

def GetMax(X, Y):
 print "\tGet Max was called from the host with",X,"and",Y
 if X > Y:
  return X
 else:
  return Y

对于python,它提供了一个模块词典的概念,一个模块词典就是一个数据结构,负责将脚本中的标识符分别映射到与它们对应的代码或是数据上,如果在c程序中我们要调用getMax函数,我们就需要用脚本词典去获得一个包含有函数GetMax的python对象。如下:
  
PyObject *pName = PyString_FromString("test");
        PyObject * pModule = PyImport_Import(pName);
   
     if(!pModule)
     {
         printf("could not open script \n");
         return 0;           
     }

 PyObject *pDict = PyModule_GetDict(pModule);

然后我们获得GetMax函数
 PyObject *pFunc = PyDict_GetItemString(pDict, "GetMax");

在我们向该函数中传递两个参数,python使用是tuple结构来传递参数

 PyObject *pParams = PyTuple_New(2);
 PyObject *pCurrParam;
 pCurrParam = PyInt_FromLong(16);
 PyTuple_SetItem(pParams, 0, pCurrParam);
 pCurrParam = PyInt_FromLong(32);
 PyTuple_SetItem(pParams, 1, pCurrParam);

我们向GetMax函数传递了16与32,然后就要调用函数并输出返回值了,如下

 PyObject *pMax = PyObject_CallObject(pFunc, pParams);
 int max = PyInt_AsLong(pMax);

这样max就为32了

7. Python调用c语言函数
同样我们可以用python调用c语言函数,这样就能做到真正的交互了。首先定义一个c语言函数。
  PyObject * RepeatString (PyObject *pSelf, PyObject *pParams)
{
   printf("\tRepeatString was called from:\n");

   char *pstrString;
   int iRepCount;

   if(!PyArg_ParseTuple(pParams, "si", &pstrString, &iRepCount))
   {
    printf("uable to parse parameter tuple.\n");
    exit(0);
   }

   for (int i = 0; i < iRepCount; i++)
   {
    printf("\t\t%d:   %s \n", i, pstrString);
   }
   return PyInt_FromLong(iRepCount);
}

该函数接受两个参数,pSelf没有什么用处,而另一个pParams则是用来传递参数的。由于传递参数都是用tuple结构,我们就使用PyArg_ParseTuple这个函数,对于”si”,表示的是按照字符串与整数来读取参数。
然后我们在主应用程序中定义一个api来存放该函数
 PyMethodDef HostAPIFuncs [] =
 {
  {"RepeatString", RepeatString, METH_VARARGS, NULL},
  {NULL, NULL, NULL, NULL} 
 };

对于这个数组的最后一行NULL来说,表明该数组结束。
接下来我们创建一个module,用来供脚本调用
 if (!PyImport_AddModule("HostAPI"))
 {
  printf("Host API module could not be created");
 }
然后将我们定义的函数表加入这个模块
 if (!Py_InitModule("HostAPI", HostAPIFuncs))
 {
  printf("Host API module could not be initialized");
 }

创建一个python脚本test.py,然后在第一行写上
 import HostAPI

再定义一个函数用来调用HostAPI函数
 def PrintStuff():
 RepCount = HostAPI.RepeatString("String repetition", 4)
 
最后我们再在主程序中调用PrintStuff函数,就可以了
总体程序如下:
 //create a module
 if (!PyImport_AddModule("HostAPI"))
 {
  printf("Host API module could not be created");
 }
  
 //create a function table
 PyMethodDef HostAPIFuncs [] =
 {
  {"RepeatString", RepeatString, METH_VARARGS, NULL},
  {NULL, NULL, NULL, NULL} 
 };

 //initial the module with the function table
 if (!Py_InitModule("HostAPI", HostAPIFuncs))
 {
  printf("Host API module could not be initialized");
 }

 //load a python script
 PyObject *pName = PyString_FromString("test");
    PyObject * pModule = PyImport_Import(pName);

 if(!pModule)
    {
        printf("could not open script \n");
        return 0;           
    }

 //get the module dict
 PyObject * pDict = PyModule_GetDict ( pModule );
 
 //get the function with the dict
 PyObject * pFunc = PyDict_GetItemString ( pDict, "PrintStuff" );
 
 //call the function
 PyObject_CallObject ( pFunc, NULL );

 Py_XDECREF ( pFunc );
 Py_XDECREF ( pDict );
 Py_XDECREF(pModule);
 Py_XDECREF(pName);

这样就完成了python与c的集成,不过这只是一些简单的应用,具体还是要参考python manual。(以上代码来自于《游戏脚本高级编程》)

0 0
原创粉丝点击