python 调用c语言库_python调用c程序

python语言可以调用c程序,其处理的基本流程如下:

创建c程序功能代码

一、创建c源程序文件py_test.c

这是程序的具体功能代码,也就是python需要调用的c源程序。

示例代码写了三个方法,最终的效果是python可以调用这三个方法。

/*

* File : py_test.c

*

* Change Logs:

* Date Author Notes

* 2018-09-22 dolphin the first version

*/

#include

#include

#include

/* 求阶乘的函数 */

int fac(int n){

if(n < 2)

return 1;

return n*fac(n-1);

}

/* 字符串逆序的函数 */

/* 比如:输入abcdefg,返回gfedcba */

char *reverse(char *s) {

char t,*p = s ,*q = (s+strlen(s)-1);

while(s && (p

t = *p;

*p++ = *q;

*q-- = t;

}

return s;

}

/* 用公式计算pi的函数,对应公式如下:

pi/2 = 1+1/3+1/3*2/5 + 1/3*2/5*3/7 + 1/3*2/5*3/7*4/9+......

*/

char *pi_fun(int len, char *ans)

{

int i; //len为小数长度

int numberator = 1,denominator = 3,result,carry;

int flag = 1,count = 0; //继续循环的标志及循环的次数

char *pi,*temp; //指向保存pi值和临时计算结果的数据

len += 2; //增加两位

printf("len = %d\n",len);

pi = (char*)malloc(sizeof(char)*(len+1)); //分配保存pi值的内存

temp = (char*)malloc(sizeof(char)*len); //分配保存呢临时值的内存

for(i = 0; i < len; i++) //初始化数组

{

pi[i] = temp[i] = 0;

}

pi[1] = 2; //置初值

temp[1] = 2;

while(flag && (++count < 2147483647)) //int的最大值 2147483647

{

carry = 0;

for(i = len-1; i > 0; i--) //从低位到高位相乘

{

result = temp[i] * numberator + carry; //用每一位去乘,再加上进位

temp[i] = result % 10; //保存个数

carry = result / 10; //进位

}

carry = 0;

for(i = 0; i < len; i++) //有高位到低位进行除法运算

{

result = temp[i] + carry*10; //当前位加上前一位的余数

temp[i] = result / denominator; //当前位的整数部分

carry = result % denominator; //当前位的余数,累加到下一位的运算

}

flag = 0; //清除标志

for(i = len-1; i > 0; i--)

{

result = pi[i] + temp[i]; //将计算结果累加到result中

pi[i] = (result % 10); //保留一位

pi[i-1] += result / 10; //向高位进位

flag |= temp[i]; //若temp中的数全为0,退出循环

}

numberator++; //累加分子

denominator += 2; //累加分母

}

for(i = 0; i < len; i++)

{

pi[i] = pi[i] + '0';

}

pi[0]= pi[1];

pi[1]= '.';

pi[len] = '\0';

printf("\n计算了%d次\n",count); //输出循环次数

strcpy(ans, pi);

free(pi);

free(temp);

return ans;

}

/* test函数 */

int test(void)

{

return 0;

}

二、创建.h头文件py_test.h

完成功能函数的头文件,声明了py_test.c中的功能函数,方便调用。

#ifndef PY_TEST_H_

#define PY_TEST_H_

char *pi_fun(int len, char *ans);

int fac (int n) ;

char *reverse(char *s) ;

int test(void) ;

#endif

python类型适配

一、写wrapper文件py_testwrapper.c

这个wrapper文件也是一段c语言代码,可以参考官方的文件Extending Python with C or C++,步骤如下:

1、包含Python.h这个头文件,这个头文件在python安装目录下的include目录下找到。

2、包含py_test.h这个头文件,这个就是创建的功能函数的头文件。

3、给py_test.c这个源程序中的每个方法都要设置一个wrapper函数,它以PyObject为返回值,并且每个函数都有两个参数PyObject *self和PyObject *args,用来传入数据。

4、添加PyMethodDef,用来定义方法名以及方法名与wrapper函数的对应关系。

5、添加PyModuleDef,用来定义模块名和该模块所具有的方法。

6、在PyInit_fun中通过PyModule_Create函数创建模块。

下面就是这个wrapper文件的完整代码:

/*

* File : py_testwrapper.c

*

* Change Logs:

* Date Author Notes

* 2018-09-22 dolphin the first version

*/

#include

#include

#include

#include "py_test.h"

/**int PyArg_ParseTuple(PyObject *arg, const char *format, ...);**/

/* fac功能的wrapper函数 */

static PyObject *py_test_fac(PyObject *self, PyObject *args)

{

int num;

int ans;

PyObject *retval;

//int ok = PyArg_ParseTuple(args, ""); /* No arguments */ /* Python call: f() */

//int ok = PyArg_ParseTuple(args, "s", &s); /* A string */ /* Python call: f('whoops!') */

//int ok = PyArg_ParseTuple(args, "(ii)s#", &i, &j, &s, &size);/* A pair of ints and a string, whose size is also returned */

/* Python call: f((1, 2), 'three') */

//const char *file;

//const char *mode = "r";

//int bufsize = 0;

//int ok = PyArg_ParseTuple(args, "s|si", &file, &mode, &bufsize);/* A string, and optionally another string and an integer */

/* Python calls:f('spam')、f('spam', 'w')、f('spam', 'wb', 100000) */

//int left, top, right, bottom, h, v;

//int ok = PyArg_ParseTuple(args, "((ii)(ii))(ii)",&left, &top, &right, &bottom, &h, &v);

/* A rectangle and a point */

/* Python call:f(((0, 0), (400, 300)), (10, 10))*/

//Py_complex c;

//int ok = PyArg_ParseTuple(args, "D:myfunction", &c);

/* a complex, also providing a function name for errors */

/* Python call: myfunction(1+2j) */

//按整形"i"获得传入的整形数据,存入num

if (!PyArg_ParseTuple(args,"i",&num))

return NULL;

//调用fac,求阶乘

ans = fac(num);

//按整形"i"将结果装入retval

retval = (PyObject *)Py_BuildValue("i", ans);

return retval;

}

/* reverse功能的wrapper函数,因python中有reverse函数,使用doppel替代 */

static PyObject *py_test_doppel(PyObject *self, PyObject *args)

{

char *src;

char *mstr;

PyObject *retval;

//按字符串"s"获得传入的整形数据,存入src

if (!PyArg_ParseTuple(args,"s",&src))

return NULL;

//申请存储空间

mstr = malloc(strlen(src) + 1);

//拷贝src到mstr

strcpy(mstr,src);

//调用reverse方法,逆序字符串

reverse(mstr);

//按字符串"ss"将两个字符串装入retval

retval = (PyObject *)Py_BuildValue("ss",src,mstr);

//释放空间

free(mstr);

return retval;

}

/* pi功能的wrapper函数 */

static PyObject *py_test_pi(PyObject *self, PyObject *args)

{

char *mstr;

int num ;

//int result;

PyObject *retval;

//按整形"i"获得传入的整形数据,存入num

if (!PyArg_ParseTuple(args,"i",&num))

return NULL;

//申请存储空间

mstr = (char*)malloc(sizeof(char)*(num + 3));

//调用pi_fun方法

pi_fun(num, mstr);

//按字符串"s"将结果装入retval

retval = (PyObject *)Py_BuildValue("s",mstr);

//释放空间

free(mstr);

return retval;

}

/* test功能的wrapper函数 */

static PyObject *py_test_test(PyObject *self,PyObject *args)

{

PyObject *retval;

//调用test方法

test();

retval = (PyObject *)Py_BuildValue("");

return retval;

}

/* 将上述封装的wrapper函数添加到PyMethodDef中 */

static PyMethodDef py_testMethods[] = {

{"fac",py_test_fac,METH_VARARGS},

{"doppel",py_test_doppel,METH_VARARGS},

{"test",py_test_test,METH_VARARGS},

{"pi",py_test_pi,METH_VARARGS},

{NULL,NULL},

};

#if 0

/* python2对应的初始化python模块的方法 */

void initpy_test(void)

{

Py_InitModule("py_test",py_testMethods);

}

#else

/* python3对应的初始化python模块的方法 */

static struct PyModuleDef pytestmodule = {

PyModuleDef_HEAD_INIT,

"py_test", /* name of module */

NULL, /* module documentation, may be NULL */

-1, /* size of per-interpreter state of the module,

or -1 if the module keeps state in global variables. */

py_testMethods

};

/* The initialization function must be named PyInit_name(),

where name is the name of the module,

and should be the only non-static item defined in the module file */

PyMODINIT_FUNC PyInit_py_test(void)

{

return PyModule_Create(&pytestmodule);

}

#endif

编译、安装

一、编译

创建setup.py文件,以便使用python的自带模块进行

#incoding:utf-8

from distutils.core import setup,Extension

#模块名

MOD = 'py_test'

#资源(要编译和链接的代码文件)

source = ['py_test.c','py_testwrapper.c']

#调用setup函数,编译和链接

setup(name=MOD,ext_modules=[Extension(MOD,sources=source)])

打开终端命令行窗口,进入文件目录,输入“python3 setup.py build”来编译(可能需要根据提示安装对应操作系统的工具链)。

二、安装

编译完成过后,当前文件目录会出现“build”文件夹,里面就是编译后的内容。

编译完成后我们还要将它们安装到python的库中,可以通过命令“sudo python3 setup.py install”来安装。

即将可执行的功能模块安装到了python库中,在python安装目录下Lib目录的site-packages文件夹下。

以后便可通过“import”将模块导入,使用模块中的具体功能。

测试

以下在python中来调用我们自己的c程序进行测试,测试程序testpython.py如下:

#incoding:utf-8

import py_test

print("-"*50)

print(py_test.fac(10)) #调用fac()求阶乘的函数

print(py_test.doppel("This is my world"))#调用逆序函数

print("-"*50)

运行程序"python3 testpython.py",程序将运算的结果打印在终端窗口中:

我们有一个用C语言实现的运算圆周率任意位小数的模块,为了比较运算速度,用python实现同样功能的python模块"pi_fun.py"如下,其中py3是与C语言完全对应的python函数,其它两种算法("pi"和"pi2")会涉及大数运算,并未直接拿来比较:

import time

import numpy as np

class pi_fun(object):

def pi(places=10):

# 3 + 3*(1/24) + 3*(1/24)*(9/80) + 3*(1/24)*(9/80)*(25/168)

# The numerators 1, 9, 25, ... are given by (2x + 1) ^ 2

# The denominators 24, 80, 168 are given by (16x^2 -24x + 8)

extra = 8

one = 10 ** (places+extra)

t, c, n, na, d, da = 3*one, 3*one, 1, 0, 0, 24

while t > 1:

n, na, d, da = n+na, na+8, d+da, da+32

t = t * n // d

c += t

return c // (10 ** extra)

def pi_t(n=10):

#t1 = time.ticks_us()

t = pi(n)

#t2 = time.ticks_us()

#print('elapsed: ', time.ticks_diff(t2,t1)/1000000, 's')

return t

def pi2(n=10):

r = 6 * (10 ** n) * 1000

p = 0

k = 0

c = r // 2

d = c // (2 * k + 1)

while d > 0:

p = p + d

k = k + 1

k2 = 2 * k

c = c * (k2 - 1) // (4 * k2)

d = c // (k2 + 1)

return p // 1000

def pi2_t(n=10):

#t1 = time.ticks_us()

t = pi2(n)

#t2 = time.ticks_us()

#print('elapsed: ', time.ticks_diff(t2,t1)/1000000, 's')

return t

def pi3(n =10):

numberator = 1

denominator = 3

result = 0

carry = 0

flag = 1

count = 0

len = n + 2; #增加两位

pi = [0 for x in range(0, len+1)]#(char*)malloc(sizeof(char)*(len+1)); //分配保存pi值的内存

temp = [0 for x in range(0, len+1)]#(char*)malloc(sizeof(char)*len); //分配保存呢临时值的内存

pi[1] = 2;#置初值

temp[1] = 2;

while flag > 0 and count < 2147483647: #int的最大值 2147483647

count = count + 1

carry = 0;

for j in range(0, len-1):

#for i = len-1; i > 0; i--) #从低位到高位相乘

result = temp[len -1 - j] * numberator + carry; #用每一位去乘,再加上进位

temp[len - 1 - j] = result % 10; #保存个数

carry = result // 10; #进位

carry = 0;

for i in range(0, len):

#for(i = 0; i < len; i++) #有高位到低位进行除法运算

result = temp[i] + carry * 10; #当前位加上前一位的余数

temp[i] = result // denominator; #当前位的整数部分

carry = result % denominator; #当前位的余数,累加到下一位的运算

flag = 0; #清除标志

for j in range(0, len-1):

#for(i = len-1; i > 0; i--)

#{

result = pi[len - 1 - j] + temp[len - 1 - j]; #将计算结果累加到result中

pi[len - 1 - j] = (result % 10); #保留一位

pi[len - 1 - j - 1] = pi[len - 1 - j - 1] + result // 10; #向高位进位

flag = flag | temp[len - 1 - j]; #若temp中的数全为0,退出循环

#}

numberator = numberator + 1#累加分子

denominator = denominator + 2#累加分母

pi_ans = ''

pi_ans += str(pi[1])

pi_ans += '.'

for i in range(2, len):

pi_ans += str(pi[i])

return pi_ans#

if __name__ == "__main__":

try:

cal = pi_fun

print(cal.pi3(10))

finally:

print('end fun')

接下来就是为测试函数增加运算时间计算的显示,修改的"testpython.py"代码如下:

#incoding:utf-8

import py_test

import time

import numpy as np

from pi_fun import pi_fun

if __name__ == "__main__":

print("-"*50)

print(py_test.fac(10)) #调用fac()求阶乘的函数

print(py_test.doppel("This is my world"))#调用逆序函数

start = time.time()

k = py_test.pi(1000)

t1 = time.time() - start

print(t1)

print(k)

print("-"*50)

cal = pi_fun

start = time.time()

k = cal.pi3(1000)

t2 = time.time() - start

print(t2)

print(k)

print("-"*50)

print(t2/t1)

运算结果如图所示,两者运算1000位圆周率小数结果完全一样,但消耗的时间有56倍差异:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2022 / 01/ 30: 新版esptool 刷micropython固件指令不是 esptool.py cmd... 而是 esptool cmd... 即可;另外rshell 在 >= python 3.10 的时候出错解决方法可以查看:  已于2022年发布的: 第二章:修复rshell在python3.10出错 免费内容: https://edu.csdn.net/course/detail/29666 micropython语法和python3一样,编写起来非常方便。如果你快速入门单片机玩物联网而且像轻松实现各种功能,那绝力推荐使用micropython。方便易懂易学。 同时如果你懂C语音,也可以用C写好函数并编译进micropython固件里然后进入micropython调用(非必须)。 能通过WIFI联网(2.1章),也能通过sim卡使用2G/3G/4G/5G联网(4.5章)。 为实现语音控制,本教程会教大家使用tensorflow利用神经网络训练自己的语音模型并应用。为实现通过网页控制,本教程会教大家linux(debian10 nginx->uwsgi->python3->postgresql)网站前后台入门。为记录单片机传输过来的数据, 本教程会教大家入门数据。  本教程会通过通俗易懂的比喻来讲解各种原理与思路,并手把手编写程序来实现各项功能。 本教程micropython版本是 2019年6月发布的1.11; 更多内容请看视频列表。  学习这门课程之前你需要至少掌握: 1: python3基础(变量, 循环, 函数, 常用, 常用方法)。 本视频使用到的零件与淘宝上大致价格:     1: 超声波传感器(3)     2: MAX9814麦克风放大模块(8)     3: DHT22(15)     4: LED(0.1)     5: 8路5V低电平触发继电器(12)     6: HX1838红外接收模块(2)     7:红外发射管(0.1),HX1838红外接收板(1)     other: 电表, 排线, 面包板(2)*2,ESP32(28)  

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值