python调用c/c++时string的传入与返回深入分析
使用ctypes可以轻松实现在python调用c/c++的库,但是这貌似没有对string类型的传入和返回有很好的支持。当把string类型str直接传进c/c++的函数时,发现strlen(str)永远是1。后来我强行输出传入的char* s后面的几位s[0]、s[1]、s[2]、s[3]……时,发现输出是a b c d e f g,每个char输出后都会有个空格,然后我再输出(int)s[0]…..发现那些空格都是’\0’。因此strlen(str)是1原因很明显是因为其读到了’\0’就停下来了。而python的string的一个字符明显是占了2byte的,当字符为英文字母时,后1byte为0,前1byte储存ascII码,这估计是为了支持中文这些复杂的文字,而char*是按照1byte为单位进行读取和写入的,所以就有了上面的现象。所以c/c++处理输入的python的string类型变量时,需要额外传入一个len(str)来获取string的长度,然后再以2byte为单位进行处理。
传入的问题解决了,而返回的问题更麻烦!
c的函数调用完后会自动delete掉函数内开辟的内存,所以返回一个char*指针是没有意义的。那么代替返回值的一个方法是直接改变python的string而不需要返回。这样的话,使用直接传进来的string变量是不行的,因为那是一个复制的变量而不是变量本身。正确的方法是传入那个string变量的指针(地址)。ctypes提供了一个c_wchar_p类型的指针可以用来获取string指针(地址):p=c_wchar_p(str).然后把p当参数传进去就可以了。完整代码如下:
c++代码:
#include <iostream>
#include<cstring>
using namespace std;
//字符串翻转函数,仅限英文
extern "C" _declspec(dllexport) void reverse(char* s,int len)
{
for(int i=0;i<len*2;i++)
cout<<s[i];
cout<<endl;
char* sc=new char[len];
for(int i=0;i<len;i++)
{
sc[i]=s[i*2];//下标乘2跳过'\0'
}
for(int i=0;i<len;i++)
s[i*2]=sc[len-1-i];
}
python3.5.2代码:
#coding=utf-8
import ctypes
from ctypes import *
ll = ctypes.cdll.LoadLibrary
lib = ll("D:/py/CDll/Debug/CDll.dll")
str='abcdefg'
p=c_wchar_p(str)
rst=lib.reverse(p,len(str))
print(p.value)
输出结果如下: