Python 调用 C/C++ 的程序主要有两种方式:

使用 ctypes 调用动态库

ctypes 的方式相对来说成本较低,首先 ctypes 是内置库,使用方便,使用的过程中与 C/C++ 动态库的逻辑是完全独立的,互相可以单独维护。但是相对也有明显的缺点,C++ 在编译后的函数名会变,ctypes 使用起来不方便,API 相对也比较繁琐,写起来略微麻烦一些,使用出错的话会导致进程退出。

本文主要介绍 ctypes 的基本用法,可以对现有的 C/C++ 代码进行简单的二次封装后进行使用。笔者认为 ctypes 本身还是比较适合轻量级的使用场景,如果逻辑较为复杂的,请考虑使用 C/C++ 扩展的方式。

本文的 Python 以 2.7 版本为例,编译使用 gcc。

简单示例

写一个简单的 Hello 来说明一下最基本的用法。首先定义一个简单的 c 函数。

//hello_module.c

#include

int hello(const char* name) {

printf("hello %s!\n", name);

return 0;

}

编译生成动态库,动态库不同的系统后缀不同(Windows 的 dll,Linux 的 so,Mac 的 dylib),需要注意,本文以 so 为例。

gcc -fPIC -shared hello_module.c -o hello_module.so

通过 ctypes 来进行动态库加载及函数调用,注意 windows 的调用方式有专有的 API。

import ctypes

lib = ctypes.cdll.LoadLibrary("hello_module.so")

lib.hello("world") # hello world!

以上便是简单的 ctypes 使用流程,加载动态库,然后就可以调用动态库中的函数。

有几点需要注意的地方:

类型的隐私转换的,python 的 str 转换为了 c 的 const char*

默认的函数返回值认为是 int,不为 int 的需要自行修改

函数的参数类型未指定,只能使用 ctypes 自带的类型隐私转换

基础类型可以参考官方文档的对应表格,需要额外说明的一点是,int 和 uint 都有对应的 8、16、32、64 的类型可供使用。

数组和指针类型

基本类型中只包含了 c_char_p 和 c_void_p 两个指针类型,其他的指针类型该如何使用?数组该如何定义和使用?我们来看看这两个类型的使用。

编写一个为数组求和的函数。

//sum_module.c

#include

int sum(int a[], size_t len) {

int ret = 0;

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

ret += a[i];

}

return ret;

}

int sum2(int* a, size_t len) {

int ret = 0;

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

ret += a[i];

}

return ret;

}

和上面一样进行编译,生成动态库

gcc -fPIC -shared sum_module.c -o sum_module.so

像之前一样来使用,看下会怎样。

import ctypes

lib = ctypes.cdll.LoadLibrary("sum_module.so")

lib.sum([1, 2, 3], 3)

#Traceback (most recent call last):

# File "demo.py", line 7, in

# lib.sum([1, 2, 3], 3)

#ctypes.ArgumentError: argument 1: : Don't know how to convert parameter 1

会发现 ctypes 报错了,不知道类型如何进行转换,也就是说 ctypes 的隐式转换是不支持数组类型的。

我们需要用 ctypes 的数组来传参数。

import ctypes

lib = ctypes.cdll.LoadLibrary("sum_module.so")

array = (ctypes.c_int * 3)(1, 2, 3)

print lib.sum(array, len(array))

i = ctypes.c_int(5)

print lib.sum(i, 1)

ctypes 的数组定义就是用 ctypes 中的类型 * 大小。

下面我们看一下指针的用法。

import ctypes

lib = ctypes.cdll.LoadLibrary("sum_module.so")

i = ctypes.c_int(5)

lib.sum2.argtypes = (ctypes.POINTER(ctypes.c_int), ctypes.c_size_t)

print lib.sum2(ctypes.pointer(i), 1)

POINTER 是用来定义指针类型,pointer 用来获取一个变量的指针,相当于 C 里面的 &。

pointer 的用法需要注意的是,必须在 ctypes 类型上使用,不能在 python 类型上使用。

import ctypes

i = ctypes.c_int(5)

print ctypes.pointer(i) # <__main__.LP_c_int object at 0x10566f7a0>

i = 5

print ctypes.pointer(i) # TypeError: _type_ must have storage info

这就是数组和指针的基本使用方式,注意指针和数组的区分,这里定义的 sum 和 sum2 只是举例,sum2 第一个参数也可以接受数组,这个和在 C 里面是一样的。

函数参数类型和返回值类型

之前的例子只有一个明确指定了参数类型,没有指定返回类型。返回类型默认是 int,如果需要返回非 int 的类型就需要进行指定。

指定参数类型的好处在于,ctypes 可以处理指针的转换,无需代码中进行转换。

继续使用上一个 sum2 函数为例。

i = ctypes.c_int(5)

lib.sum2.argtypes = (ctypes.POINTER(ctypes.c_int), ctypes.c_size_t)

print lib.sum2(ctypes.pointer(i), 1)

print lib.sum2(i, 1)

可以使用 pointer(i) 和 i 作为 sum2 的第一个参数,会自动处理是否为指针的情况。

结构体

结构体在 ctypes 需要进行类的定义,类型和指针的使用方式和之前一致。

下面我们看一个 struct 定义的实例。

import ctypes

"""

typedef struct _user {

int type;

uint64_t userid;

char username[64];

unsigned int created_at;

} user;

"""

class User(ctypes.Structure):

_fields_ = [

('type', ctypes.c_int),

('userid', ctypes.c_uint64),

('username', ctypes.c_char * 64),

('created_at', ctypes.c_uint),

]

print ctypes.POINTER(User) # u = User()

print ctypes.pointer(u) # <__main__.LP_User object at 0x10982c7a0>

总结

ctypes 也支持联合体 union,但是因为不常用,所以本文没有提及。有需要的可以参考官方文档。

参考资料

ctypes python_Python ctypes 使用总结相关推荐

  1. ctypes python_Python使用Ctypes与C/C++

    项目中可能会经常用到第三方库,主要是出于程序效率考虑和节约开发时间避免重复造轮子.无论第三方库开源与否,编程语言是否与当前项目一致,我们最终的目的是在当前编程环境中调用库中的方法并得到结果或者借助库中 ...

  2. python调用动态链接库windows_用win从python ctypes调用标准windows.dll的Segfault

    我试图在Linux上运行的Python脚本中从Kernel32.dll调用一些函数.正如Johannes Weiß指出的How to call Wine dll from python on Linu ...

  3. python ctypes实现api测试_Python与C之间的相互调用(Python C API及Python ctypes库)

    2010-01-24 17:58 14237人阅读 评论(11) 我实现 Python C API 此部分可以参考我原来的文章< 准备工作: 闲话少说,看看Python C API.事实上,Py ...

  4. 使用 ctypes 将 Python 运行速度提升 30 倍

    简介 当 Python 面临运算密集型任务时,其速度总是显得力不从心.要提升 Python 代码运行速度有多种方法,如 ctypes.cython.CFFI 等,本篇文章主要从 ctypes 方面介绍 ...

  5. 10.4.4 使用ctypes调用kernel32.dll中的函数

    10.4.4 使用ctypes调用kernel32.dll中的函数 2007-10-17 14:41 孙广磊 人民邮电出版社 字号:T | T 综合评级: 想读(5)  在读(0)  已读(6)   ...

  6. python ctypes模块安装_ctypes模块扩展python

    文章1 前言 朋友的公司是做GPS的,上周联系到我要帮做个程序把他们平台的车辆定位跟踪数据和省里的平台对接.看一下官方提供的三个文档,洋洋洒洒共一百多页,一大堆协议的定义甚是齐全,好在官方的文件中也带 ...

  7. python typeerror console未定义,Python ctypes加载错误:未定义的符号

    我试图用ctypes将从C源编译的共享库加载到 Python中.共享库(下面名为"libsub.so")使用了libusb库.这就是"make"所做的: gcc ...

  8. Python与C之间的相互调用(Python C API及Python ctypes库)

    2010-01-24 17:58 14237人阅读 评论(11) 收藏 举报 目录(?)[-] Python C API 准备工作: C中内嵌Python 获取返回值 利用C扩展Python Pyth ...

  9. python调用ctypes中windll中的方法超时处理_python中使用ctypes调用MinGW生成的动态链接库(dll)...

    关于gcc编译dll的我就不说了,网上举例一大堆,下面以g++为例. 假设有一个test.cpp文件如下: extern "C" { __declspec(dllexport) d ...

最新文章

  1. 使用inetaddress测试目标可达性_白盒测试工具―Winams介绍
  2. Facebook参与AI芯片设计大混战!
  3. atlas mysql 数据库同步_Atlas实现数据库读写分离
  4. 使用自连接、for xml path('')和stuff合并显示多行数据到一行中(转)
  5. Scrapy-css选择器
  6. Java 动态代理及 RPC 框架介绍
  7. SAP ABAP二分查找(binary search)实际问题的深度分析
  8. what to look if you want to debug your docsify based website
  9. 字母异位词分组—leetcode49
  10. 如何清空c盘只剩系统_C盘满了怎么办?除了重装系统,还有这些办法!
  11. 截图:截取当前程序的界面,并保存到bmp图片中。
  12. Shiro学习总结(10)——Spring集成Shiro
  13. 阿里云河源数据中心正式开服 疫情期间曾2小时扩容1万台云服务器
  14. 【转载】2008年世界最大50家石油公司综合排名(按六项指标综合测算)
  15. JS实现改变复选框选中行中指定单元格背景色(状态改变事件)
  16. [sipdroid]3CX voip 服务器的搭建教程---个人实践版
  17. 事件分发(EventDispatcher)模式
  18. PS——出现“Not a PNG file“报错的一种解决方法
  19. FFmpeg视频剪辑拼接
  20. AM335x启动流程(bootrom)

热门文章

  1. 进程和线程的概念、区别和联系
  2. PHP被忽视的编码规范
  3. android studio 代码缩略图,android studio 设置模板
  4. java中qq中拉伸的文件,delphi中如何实现QQ中的截图并实现拉伸放大移动的功能
  5. CentOS 安装宋体字体
  6. Spring事务 Transaction rolled back because it has been marked as rollback-only
  7. php中get和set区别,javascript中set与get方法详解
  8. mkl_def.dll文件加载失败
  9. spring 事务笔记(四)
  10. php客户端连接远程redis,phpredis客户端连接Redis--华为云DCS for Redis使用经验