python调用c

python一个非常的大的优点就是开发效率高,非常不好的缺点就是执行效率低;然而c语言有个则刚好相反。还有一点python的对源码的保护做不到,即使你用py2exe,pyinstaller这样的方法也是很容易被反编译出来。但是c写的代码反编译的难度就极大地增加。所以如果你写的代码里面如果包含了一些敏感的东西,那么你可以把这段代码使用c来写。

 

那么我们是不是可以结合起来使用呢?

答案是完全可以,用c来写一个动态库/共享库,然后在python中调用。

python 的解释器本身就是用c写的,所以调用c是很方便的,调用的方法不止一种,我们这里介绍使用ctypes这种方式。

我们会写一个测试代码来演示怎么在python中调用c函数,包括python传整型和字符串参数给c库,c库中返回整型和字符串。这个测试将在windows xp平台+python2.7实施。

接下来我们把要做的事情分成2个阶段,用c编写一个动态库,在python中调用这个动态库。

 

 

c编写一个动态库

使用vc6创建一个空的win32动态库,添加2个文件

testcdll.c

tsetcdll.def

 

testcdll.c的内容如下:

#include <stdlib.h>
#include <string.h>


int add( int a, int b )
{
	return a + b;
}


char* pStr = 0;
int nMax = 128;
char* makestring( )
{
	pStr = ( char* )malloc(nMax);
	memset( pStr, 0, nMax );
	strcpy( pStr, "test is test string" );
	
	return pStr;
}

void delstring( void )
{
	if ( 0 != pStr )
	{
		free( pStr );
		pStr = 0;
	}
}

char* catstring( char* pinput )
{
	if ( 0 == pinput )
	{
		return 0;
	}
	if ( 0 == pStr )
	{
		pStr = ( char* )malloc(nMax);
	}
	memset( pStr, 0, nMax );
	strcpy( pStr, "test is test string--" );
	strcat( pStr, pinput );
	return pStr;
}

 

然后编译,得到后面测试要用到的testcdll.dll

如果你不想用IDE的话, 你可以直接使用命令行来编译:

 

cl /LD testcdll.c tsetcdll.def  /link /out:testcdll.dll

 

 

 

调用这个动态库

 

因为我们的测试比较简单所以我们就不写源码文件,直接在解释器中写测试代码了。

打开命令行cmd,cd到刚才我们生成dll的文件夹,执行python

到解释器界面,依次执行下面的命令:

 

 

>>> from ctypes import *
>>> hd = cdll.LoadLibrary('FoxLicenseMgr.dll')
>>> hd.add( 2, 3 )
5
>>> hd.makestring.restype = c_char_p
>>> hd.makestring()
'test is test string'
>>> hd.delstring()
1
>>> s1 = 'python'
>>> cs1 = c_char_p( s1 )
>>> hd.catstring(cs1)
12068640
>>> hd.catstring.restype = c_char_p
>>> hd.catstring(cs1)
'test is test string--python'
>>> dir(hd)
['_FuncPtr', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '_
_getattr__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__modul
e__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__si
zeof__', '__str__', '__subclasshook__', '__weakref__', '_func_flags_', '_func_re
stype_', '_handle', '_name', 'catstring', 'delstring', 'makestring']
>>> exit()

 

对上面语句稍作解释,

 

 

from ctypes import *

 

因为我们使用的是ctypes的这种方式,需要导入ctypes。

 

 

hd = cdll.LoadLibrary('testcdll.dll')

加载我们之前生成的动态库,因为我们已经cd到testcdll.dll所在的目录所以不用加全路径,否则你需要写全路径的。

 

 

hd.add( 2, 3 )

直接调用add函数,传进2个参数,参数不需要额外的转换,直接传进去,有些类型是不可以直接传的,需要做个转换,这个后面会提到。调用这一句后,就直接输入结果到控制台上结果为5

 

调用返回为字符串的函数的时候,需要设置返回类型,否则就会返回一整型值,这是python调用c函数的默认的返回值,如上面调用catstring的之前没有设置返回值,结果返回一个数值

 

>>> hd.catstring(cs1)
12068640

 

设置返回类型使用下面的语法:

 

hd.makestring.restype = c_char_p

因为我们的返回类型是char*, 所以使用c_char_p,这个和char*是对应的。其他的python的ctypes的类型和c类型的映射关系如下:

 

ctypes type C type Python type
c_bool _Bool bool (1)
c_char char 1-character string
c_wchar wchar_t 1-character unicode string
c_byte char int/long
c_ubyte unsigned
char
int/long
c_short short int/long
c_ushort unsigned
short
int/long
c_int int int/long
c_uint unsigned
int
int/long
c_long long int/long
c_ulong unsigned
long
int/long
c_longlong __int64 orlonglong int/long
c_ulonglong unsigned
__int64
orunsignedlonglong
int/long
c_float float float
c_double double float
c_longdouble long
double
float
c_char_p char
*
(NUL terminated)
string or None
c_wchar_p wchar_t
*
(NUL terminated)
unicode or None
c_void_p void
*
int/long or None

 

调用makestring()来返回一个字符串:

 

>>> hd.makestring()
'test is test string'

 

如果传入的是字符串,也需要做一个转换

 

>>> s1 = 'python'
>>> cs1 = c_char_p( s1 )

然后再传入,因为这个函数的返回的是字符串因此也需要设置返回类型:

 

>>> hd.catstring.restype = c_char_p
>>> hd.catstring(cs1)
'test is test string--python'

 

最后使用dir来查看这个hd的都有那些可用的方法。

 

 

完。

版权所有,禁止转载. 如需转载,请先征得博主的同意,并且表明文章出处,否则按侵权处理.

    分享到:

One Reply to “python调用c”

留言

你的邮箱是保密的 必填的信息用*表示