四. python调用C语言中函数

一. 引入

python调用c语言函数时,主要有以下几个问题,调用时向C语言传入参数,python调用后接受C语言返回的数据

二. 调用具体操作

1. 传参并接收返回值(支持中文字符串)

C语言函数:demo.c
调用的 我们指定了调用testmain函数时,需要传入一个数字和一个字符串,防止返回的中文出现乱码,这里使用base64位对字符串进行了编码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <memory.h>
#include <stdlib.h>
#include <curl/curl.h>
#include "demo.h"
//提供给python调用的函数
char *testmain(char *argv[1]) {
printf("接收到%s\n",argc);
printf("接收到%s\n",argv[0]);
result = "接受到了数据";
return base64Encode(result, strlen(result ));
}

char base64Alphabet[]=
{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/','='};

char *base64Encode(const char* source, const int sourceLength){
/*命名为padding不准确,不过先不改了^_^*/
unsigned int padding = sourceLength%3;
unsigned int resultLength = sourceLength%3 ? ((sourceLength)/3 + 1)*4 : (sourceLength)/3*4;
unsigned int i=0, j=0;
unsigned char* be_result = (unsigned char*)malloc(resultLength + 1);
memset(be_result, 0, resultLength+1);

unsigned char temp = 0;
for (i=0,j=0; i<sourceLength; i+=3, j+=4)
{
if (i+2 >= sourceLength)
{
be_result[j] = (source[i]>>2) & 0x3F;
if (padding==1)
{
//这里padding实际为2
be_result[j+1] = ((source[i] & 0x03)<<4 ) & 0x3F;
be_result[j+2] = 0x40;
be_result[j+3] = 0x40;
break;
}
else if (padding==2)
{
//这里padding实际为1
be_result[j+1] = (((source[i] & 0x03)<<4) | ((source[i+1]>>4) & 0x0F));
be_result[j+2] = ((source[i+1] & 0x0f)<<2) & 0x3F;
be_result[j+3] = 0x40;
break;
}
}

be_result[j] = (source[i]>>2) & 0x3F;//最高两位要变为0
be_result[j+1] = (((source[i] & 0x03)<<4) | ((source[i+1]>>4) & 0x0F));//0x03(只取最低两位,其余位为0) 0x0F(只取低四位,其余位为0)
be_result[j+2] = (((source[i+1] & 0x0f)<<2) | ((source[i+2]>>6) & 0x03));
be_result[j+3] = (source[i+2] & 0x3F);
}

for ( j=0; j<resultLength; ++j)
{
be_result[j] = base64Alphabet[be_result[j]];
}
return be_result;
}
C语言头文件:demo.h
char *base64Encode(const char* source, const int sourceLength);

编译:Linux 下
gcc demo.c -fPIC -shared -o demo.so

Python文件:testDemo.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import os
import ctypes
import base64
import json

def recognitionVoice(v_name):
str1 = ctypes.c_char_p(bytes(v_name, 'utf-8'))
voicenames = (ctypes.c_char_p*1)(str1)
lib = ctypes.CDLL('./demo.so')
lib.testmain.restype = ctypes.POINTER(ctypes.c_ubyte) #让函数返回ubyte* 类型
p = lib.testmain(voicenames)
list = []
for n in range(255):
if p[n] == 0:
break;
list.append(chr(p[n]))#ascll转换
list = ''.join(list)
decodestr = base64.b64decode(list).decode()
print(decodestr)

if __name__=="__main__":
recognitionVoice("测试一下")

Alt text

2. 只能传递参数

上面是一种调用方式,可以传值,可以接收到返回的值,下面还有一种简单的调用方式,只是这种方式只能传递参数,可以使用同步和异步的:

demo.c 内容如下:

1
2
3
4
5
6
7
8
#include <memory.h>
#include <stdlib.h>
#include <curl/curl.h>
#include "demo.h"
int main(int argc,char *argv[]) {
printf("接收到%s\n",argv[1]);
return 0;
}

编译的指令为:
gcc demo.c -o demo.so

testDemo01.py 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#coding=utf-8
import os

#同步
def speakvoice(str):
os.system("./demo.so "+str)

#异步
def speakvoice_asyn(str):
os.popen("./demo.so "+str)

if __name__ == '__main__':
speakvoice("测试一下")

Alt text

这里要注意的是,用这种方法只能传递参数,不能接收到返回的数据