Python3调用C程序(超详解)

时间:2022-08-28 23:45:42

Python3调用C程序(超详解)

Python为什么要调用C?

1.要提高代码的运算速度,C比Python快50倍以上

2.对于C语言里很多传统类库,不想用Python重写,想对从内存到文件接口这样的底层资源进行访问

Python调用C的方法:

Python调用C的方法通常有3种:

1.SWIG,编写一个额外的接口文件来作为SWIG(终端工具)的入口

2.通过CTypes调用

3.使用Python/C API方法

第一种方法大多数情况下会带来不必要的麻烦,我并没有试验,本文只针对2,3方法作详细说明

通过CTypes调用:

Python中的ctypes模块可能是Python调用C方法中最简单的一种。ctypes模块提供了和C语言兼容的数据类型和函数来加载dll文件,因此在调用时不需对源文件做任何的修改。也正是如此奠定了这种方法的简单性。

下面是python文件的代码:

from ctypes import *	#pip ctypes库,并导入库
test = CDLL("./test.dll") #调用当前目录下叫test的dll文件,dll文件是C生成的动态链接库
result =test.sum(5,10) #调用库里的函数sum,求和函数
print(result) #打印结果

接下来用C语言编写dll动态链接库,这里使用VS:

Python3调用C程序(超详解)

Python3调用C程序(超详解)

单击头文件,新建项:

Python3调用C程序(超详解)

添加源文件:

Python3调用C程序(超详解)

在头文件test.h中加入如下代码:

#pragma once

#ifdef BUILD_TEST
#define API_SYMBOL __declspec(dllexport)
#else
#define API_SYMBOL __declspec(dllimport)
#endif
//宏定义,导出或者导入// extern "C" API_SYMBOL int sum(int x, int y);
//导出函数//

在源文件test.cpp中加入如下代码:

#define BUILD_TEST  //使导出函数生效
#include "test.h"
#include "stdio.h"
#include "pch.h" int sum(int a, int b) {
return a + b;
}

注意,这里要点击64位,再点击生成(因为目前大部分电脑安装Python解释器是64位的,否则默认生成32位的动态库,会导致无法调用)这是一个很隐蔽的坑!!!

Python3调用C程序(超详解)

在生成的动态库路径下找到test.dll文件,并复制到python项目下

Python3调用C程序(超详解)

Python3调用C程序(超详解)

最后在python中运行代码,出现如下问题:

Python3调用C程序(超详解)

为了寻找问题,我将python文件中的代码替换如下,发现调用动态库是成功的,只是不能调用动态库里面的函数

from ctypes import *
from ctypes import * #pip ctypes库,并导入库
test = CDLL("./test.dll") #调用当前目录下叫test的dll文件,dll文件是C生成的动态链接库 print("加载成功") # result =test.sum(5,10) #调用库里的函数sum,求和函数
# print(result) #打印结果

Python3调用C程序(超详解)

以上流程我是参考B站一位UP主的具体教学,但还是行不通,于是我将test.cpp源文件中的代码更改如下:

#define BUILD_TEST
#include "test.h"
#include "stdio.h"
#include "pch.h" #define DLLEXPORT extern "C" __declspec(dllexport) //直接在源文件定义导出 DLLEXPORT int sum(int a, int b) {
return a + b;
}//两数相加

重复上述流程,生成dll文件,将文件放置于python项目中,然后调用,终于成功

from ctypes import *
from ctypes import * #pip ctypes库,并导入库
test = CDLL("./test.dll") #调用当前目录下叫test的dll文件,dll文件是C生成的动态链接库 print("加载成功") result =test.sum(5,10) #调用库里的函数sum,求和函数
print(result) #打印结果

Python3调用C程序(超详解)

使用Python/C API方法:

Python/C API可能是被最广泛使用的方法。它不仅简单,而且可以在C代码中操作你的Python对象。但要使用这种方法,需要用特定的方式来编写C代码,所以C代码不是原生的C(大伙要适应一下),这样才可以供python去调用。这里参照python进阶的说明博客园的一篇文章

python文件的代码如下:

import Test
x = 1
print(Test.add_one(x))

而这里的Test模块,则是需要我们自己用C语言写,C文件代码如下:

#include <Python.h>

int add_one(int a){
return a + 1;
}//这是C的原生函数,实现+1功能 static PyObject * py_add_one(PyObject *self, PyObject *args){
int num;
if (!PyArg_ParseTuple(args, "i", &num)) return NULL;
return PyLong_FromLong(add_one(num));
}//这一串代码要实现的功能如下,按照python规定的调用方式:
//1.定义一个新的静态函数,接收2个PyObject *参数,返回1个PyObject *值
//2.PyArg_ParseTuple方法将python输入的变量变成C的变量,即上述args→num
//3.紧接着调用C原生函数add_one,传入num
//4.最后将调用返回的C变量,转换为PyObject*或其子类,并通过PyLong_FromLong方法,返回python值 static PyMethodDef Methods[] = {
{"add_one", py_add_one, METH_VARARGS},
{NULL, NULL}
};//这串代码的目的是创建一个数组,来指明Python可以调用这个扩展函数:
//其中"add_one",代表编译后python调用时希望使用的函数名。而py_add_one,代表要调用当前C代码中的哪一个函数,即static PyObject * py_add_one。METH_VARARGS,代表函数的参数传递形式,主要包括位置参数和关键字参数两种
//最后如果希望添加新的函数,则在最后的{NULL, NULL}里按同样格式填写新的调用信息,比如加一些求和求乘积函数 static struct PyModuleDef cModule = {
PyModuleDef_HEAD_INIT,
"Test", /*模块名,即是生成模块后的名字,如numpy,opencv等等*/
"", /* 模块文档,可以为空NULL */
-1, /* 模块中每个解释器的状态大小,模块在全局变量中保持状态,则为-1 */
Methods//即上一步定义的Methods,说明了可调用的函数集
};//创建module的信息 PyMODINIT_FUNC PyInit_Test(void){ return PyModule_Create(&cModule);}
//module初始化

将C文件放置在python项目的同文件目录下,然后编写setup.py文件,setup.py是用来将C打包成模块的脚本文件,代码如下:

from distutils.core import setup, Extension #这里要用到distutils库
module1 = Extension('Test', sources = ['test.c']) #打包文件为test.c,这里没有设置路径,所有.c文件和setup.py放在同一目录下
setup (name = 'Test', #打包名
version = '1.0', #版本
description = 'This is a demo package', #说明文字
ext_modules = [module1])

然后在pycharm的Terminal终端输入(因为这里用的python3.5+,windows平台下python的C/C++扩展不再支持gcc的编译,并强制要求使用msvc进行编译,如果版本低于3.5,用python setup.py build这是一个隐藏的坑!!!用python setup.py build一直出问题

python setup.py build --compiler msvc #编译代码
python setup.py build --compiler msvc install #编译代码并直接将包放入当前python环境的包的路径以供调用

Python3调用C程序(超详解)

Python3调用C程序(超详解)

最后结果,顺利打包,我们在python里安装了自己的包并完成调用:

Python3调用C程序(超详解)

Python3调用C程序(超详解)

Python3调用C程序(超详解)

本文由博客一文多发平台 OpenWrite 发布!

Python3调用C程序(超详解)的更多相关文章

  1. Linux Bash命令关于程序调试详解

    转载:http://os.51cto.com/art/201006/207230.htm 参考:<Linux shell 脚本攻略>Page22-23 Linux bash程序在程序员的使 ...

  2. UIViewController中各方法调用顺序及功能详解

    UIViewController中各方法调用顺序及功能详解 UIViewController中loadView, viewDidLoad, viewWillUnload, viewDidUnload, ...

  3. 一个简单的C语言程序(详解)

    C Primer Plus之一个简单的C语言程序(详解) #include <stdio.h> int main(void) //一个简单的 C程序 { int num; //定义一个名为 ...

  4. Python调用windows下DLL详解

    Python调用windows下DLL详解 - ctypes库的使用 2014年09月05日 16:05:44 阅读数:6942 在python中某些时候需要C做效率上的补充,在实际应用中,需要做部分 ...

  5. 嵌入式Linux应用程序开发详解------(创建守护进程)

    嵌入式Linux应用程序开发详解 华清远见 本文只是阅读文摘. 创建一个守护进程的步骤: 1.创建一个子进程,然后退出父进程: 2.在子进程中使用创建新会话---setsid(): 3.改变当前工作目 ...

  6. VS2010开发程序打包详解

    VS2010开发程序打包详解 转自:http://blog.sina.com.cn/s/blog_473b385101019ufr.html 首先打开已经完成的工程,如图: 下面开始制作安装程序包. ...

  7. Thrift实现C&num;调用Java开发步骤详解

    概述 Thrift实现C#调用Java开发步骤详解 详细 代码下载:http://www.demodashi.com/demo/10946.html Apache Thrift 是 Facebook ...

  8. html5的float属性超详解(display,position, float)(文本流)

    html5的float属性超详解(display,position, float)(文本流) 一.总结 1.文本流: 2.float和绝对定位都不占文本流的位置 3.普通流是默认定位方式,就是依次按照 ...

  9. HTML中DOM核心知识有哪些(带实例超详解)

    HTML中DOM核心知识有哪些(带实例超详解) 一.总结: 1.先取html元素,然后再对他进行操作,取的话可以getElementById等 2.操作的话,可以是innerHtml,value等等 ...

随机推荐

  1. mysql 理解 int&lpar;11&rpar;

    1.这里的int(11) 与int的大小和存储字节,没有一毛钱关系,int的存储字节是4个字节,最大值为 65536*65536 = 40多亿,对于有符号的int,是20多亿.2.那么这里的(11) ...

  2. 如何判断raid1中哪块硬盘损坏?

    服务器 2块硬盘做的raid1,如果其中有一块坏掉,如何能判断是哪块坏掉? 方法①.通过硬盘硬件指示灯进行观察,一般黄灯代表硬盘存在问题,显示红灯则代表硬盘损坏.方法②.通过开机进入阵列配置进行查看, ...

  3. ecshop常用语句

    ecshop之中的IF语句: <select name="product_cat" id="product_cat" class="form-c ...

  4. 基于ubuntu和windows连接

    对于ubuntu和centos安装软件是不一样的 对于ubuntu是  apt-get install  +软件名字 但是对于centos是 yum install +软件名字 所以ubunu远程连接 ...

  5. 设计模式 - 模板方法模式&lpar;template method pattern&rpar; JFrame 具体解释

    模板方法模式(template method pattern) JFrame 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(templ ...

  6. 1707&colon; &lbrack;Usaco2007 Nov&rsqb;tanning分配防晒霜

    1707: [Usaco2007 Nov]tanning分配防晒霜 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 548  Solved: 262[Sub ...

  7. javascript实现禁止右键和F12查看源代码

    <!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...

  8. ABP官方文档翻译 3&period;4 领域服务

    领域服务 介绍 IDomainService接口和DomainService类 示例 创建接口 服务实现 使用应用服务 一些探讨 为什么只有应用服务? 如何强制使用领域服务? 介绍 领域服务(或者在D ...

  9. SoapUI 学习总结-02 断言

    一 断言 测试指定的restful api是否正常,判断它的响应值是否符合预期标准,需要用到断言知识.在soapUI里断言使用的Groovy语言.在项目中测试起来非常简单,测试过程如下. 1,准备测试 ...

  10. HTML中字体的垂直排列

    1.源代码: <html> <head> </head> <body> <div style="font-size:18px;writi ...