python与c的集成

记得在大学里和同学一起进行游戏开发,可到了后来完全无法继续下去,现在想想原因,一是自己的水平有限,另一个就是没做到游戏引擎与数据的分离,也就是没有理解脚本。那时的我根本就不知道什么叫做脚本编程,现在随着工作的深入也渐渐理解了一点。

虽然脚本语言有很多种,但是我毫不犹豫了选择了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 /* _DEBUG */

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函数,我们就需要用脚本词典去获得一个包含有函数GetMaxpython对象。如下:

             

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函数传递了1632,然后就要调用函数并输出返回值了,如下

 

       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);

 

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

 

转载于:https://my.oschina.net/siddontang/blog/263235

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值