python和c语言进行数据交互,涉及类型转换,字节对齐,字节序大小端转换等。相关模块ctypes,struct,memoryview。

一.ctypes:python和c语言使用结构体数据进行交互

场景:有一个C语言生成的动态链接库,python需要调用动态库里的函数处理数据。函数的入参是结构体类型的指针,出参是一个buffer,那么如何把python的数据转换成c语言中的结构体类型?

1.ctypes的使用

C语言代码如下

#include

typedef struct student{

char name;

short class;

double num;

int age;

}stu;

typedef struct stu_struct_array{

stu stu_array[2];

}stu_struct_array_t;

int struct_test(stu *msg, stu_struct_array_t *nest_msg, char *buff){

int index = 0;

printf("stu name: %d\n", msg->name);

printf("stu class: %d\n", msg->class);

printf("stu num: %f\n", msg->num);

printf("stu age: %d\n", msg->age);

memcpy(nest_msg->stu_array, msg, sizeof(stu));

printf("stu array index 0 name: %d\n", nest_msg->stu_array[0].name);

printf("stu array index 0 class: %d\n", nest_msg->stu_array[0].class);

memcpy(buff, msg, sizeof(stu));

printf("buff: %d %d", buff[0], buff[1]);

return 1;

}

通过-fPIC -shared选项生成动态链接库,编译命令gcc -Wall -g -fPIC -shared -o libstruct.so.0 struct_array.c

此时需要通过python调用struct_test()函数,那么如何利用python传入结构体参数呢?

方法就是利用ctypes模块组装结构体

(1)首先是结构体的组装

ctypes定义了一些和C兼容的基本数据类型:

_fields_需要包括(构体成员名称, C语言中的数据类型)组成的元组列表来初始化

from ctypes import *

# 根据结构体类型组装数据

fields_list = [("name", c_char),

("class", c_short),

("num", c_double),

("age", c_int)]

stu_value_list = [c_char(b'\x05'), c_short(1), c_double(10244096), c_int(2)]

# 创建结构体对象

class StuStruct(Structure):

# _fields_是容纳每个结构体成员类型和值的列表,可以配合自动生成fields list和value list的函数使用

_fields_ = fields_list

"""# 也可以直接初始化,适用于结构体数量不多的情况_fields_ = [("name", c_char, b'\x05),("class", c_short, 1),("num", c_double, 10244096),("age", c_int, 2)]"""

# 实例化并初始化结构体成员的值

stu_obj = StuStruct(*stu_value_list)

print("stu name:%s" % stu_obj.name)

# 这里使用的时候需要注意,结构体成员的名称不能和python内置关键字重复,如果真出现了这种情况。。。

# print(stu_obj.class)

print("stu num:%s" % stu_obj.num)

print("stu age:%s" % stu_obj.age)

# 创建嵌套结构体对象

class NestStu(Structure):

_fields_ = [("stu_array1", StuStruct * 2)

]

# 创建StuStruct的数组

stu_array = StuStruct * 2

stu_obj_list = [stu_obj, stu_obj]

# 实例化stu_array

stu_array_obj = stu_array(*stu_obj_list)

# 实例化NestStu,因为stu_array1成员是结构体数组类型,只能以同类型的实例进行初始化

nest_obj = NestStu(stu_array_obj)

# 打印信息

print("name:%s" % nest_obj.stu_array1[0].name)

print("num:%s" % nest_obj.stu_array1[0].num)

print("age:%s" % nest_obj.stu_array1[0].age)

# 载入动态链接库

struct_so = cdll.LoadLibrary("./libstruct.so.0")

# 调用函数,根据入参类型需要把结构体转换成对应的指针

stu_p = pointer(stu_obj)

nest_stu_p = pointer(nest_obj)

# ctypes模块提供了快速创建char类型数组的方法

in_buff =create_string_buffer(b"", size=100)

rest = struct_so.struct_test(stu_p, nest_stu_p, in_buff)

# 一般情况下若被调用的函数没有返回值,成功执行后则会返回0,若有其他返回值则返回对应的值

print("rest:%s" % rest)

这里使用的时候需要注意,结构体成员的名称不能和python内置关键字重复,如上述的class,如果真出现了这种情况。。。

(2)调用动态链接库,查看打印,获取输出stu name: b'\x05'

stu num: 10244096.0

stu age: 2

name: b'\x05'

num: 10244096.0

age: 2

stu name: 5

stu class: 1

stu num: 10244096.000000

stu age: 2

stu array index 0 name: 5

stu array index 0 class: 1

rest: 1

buff: 5 0

此处应该注意的一个问题是字节对齐的问题,ctypes模块提供了_pack_属性来设置字节对齐,默认不设置则跟编译器设置相同4字节对齐,如果设置为1字节对齐,需要更改代码,比如在StuStruct中加入_pack_ = 1,

# 创建结构体对象

class StuStruct(Structure):

# _fields_是容纳每个结构体成员类型和值的列表,可以配合自动生成fields list和value list的函数使用

_fields_ = fields_list

_pack_ = 1

print(sizeof(StuStruct))的输出为15,不指定字节对齐则为24。

此外,除了实现字节对齐以外,ctypes模块还提供了class BigEndingStructure()和class LittleEndingStructure(()用于创建大小端字节序的结构体,

更多方法请参照我的另一篇文章,里面详细介绍了使用Python组装C语言数据类型的方法。INnoVation:Python--ctypes(数据类型详细踩坑指南)​zhuanlan.zhihu.com指针类型

指针数组类型

结构体指针类型

结构体指针数组类型

函数指针

类型转换

获取函数返回值类型

二.处理字节流

在使用python处理二进制数据或者使用socket通信的时候,python提供了struct模块将数据转换为字节流进行处理。

1.内置方法:def calcsize(fmt)

根据给定的fmt计算calsize大小

def pack(fmt, *args)

fmt:格式控制符,主要用于指定每一个需要解析的数据大小,格式控制符对应c语言的数据类型和size如下

*args:需要pack的值的列表

return:字节对象def pack_into(fmt, buffer, offset, *args)

将args列表内的数据pack为字节流。然后写入buffer内偏移量为offset以后的区域

def unpack(fmt, string)

将string根据fmt解析为一个元组然后返回

def unpack_from(fmt, buffer, offset=0)

从buffer区域offset位置开始截取字节流然后进行转换,返回一个元组

def iter_unpack(*fmt, **string)

先使用calsize计算fmt的大小,然后每次转换string中长度为每个fmt对饮大小的字节,返回的是每次unpack产生的值组成的一个unpack_iterator。

import struct

int_byte1 = b'\x01\x00\x00\x00\x02\x00\x03\x00\x00\x00'

fmt = "=IHI"

rest = struct.iter_unpack(fmt, int_byte1)

print(type(rest))

for item in rest:

print(item)

输出:(1, 2, 3)

2.字节序的转换

因为个人业务遇到了一种情况,本机为小端字节序,但是在转换为字节流的时候需要需要转换为大端字节序且需要满足4字节对齐的情况,这个时候struct模块提供的格式控制符就不能满足需求了,无论是'>'控制符还是'!'控制符均以本机字节序和1字节对齐为准进行转换。那么要实现上述的需求,只能先转换为本机字节序的字节流,再进行字节序的转换。

# 本机字节序,4字节对齐

print(struct.pack("@BH", 1, 2))

# 大端字节序,1字节对齐

print(struct.pack(">BH", 1, 2))

# 本机字节序,1字节对齐

print(struct.pack("=BH", 1, 2))

输出:b'\x01\x00\x02\x00'

b'\x01\x00\x02'

b'\x01\x02\x00'

实现方法:字节序的不同本质上是数据在内存内部的存放顺序不同,要完成字节序的转换只要改变数据再内存中的存放顺序即可,python提供了memoryview模块让我们能够直接操作内存,实现方法如下:

import struct

import sys

# 查看本机字节序

print(sys.byteorder)

# 使用本机字节序进行转换

bytes_stream = struct.pack("@I", 2)

print("little ending strm: %s" % bytes_stream)

# memoryview只接受bytearray对象,此处需要转换

array_stream = bytearray(bytes_stream)

mem_str = memoryview(array_stream)

stream_len = mem_str.__len__()

print("msg len: %s" % stream_len)

# 改变内存内值的排列顺序

for ite in range(0, stream_len):

tmp = mem_str[ite:ite + 1].tobytes()

mem_str[ite:ite + 1] = mem_str[stream_len - ite - 1:stream_len - ite]

mem_str[stream_len - ite - 1:stream_len - ite] = tmp

if ite + 1 == stream_len - 1 - ite:

break

mem_bytes = mem_str.tobytes()

print("big ending strm: %s" % mem_bytes)

输出:little

little ending strm: b'\x02\x00\x00\x00'

msg len: 4

big ending strm: b'\x00\x00\x00\x02'

此处演示只是对单个数据进行大小端处理,多数情况下一条字节流里可能含有多个数据,那样就需要根据fmt中每个数据的长度对字节流先进行切片,然后再进行大小端转换。

python能和c语音交互吗_Python和C语言交互--ctypes,struct相关推荐

  1. python与c 交互原理_PYTHON 与C相互交互调用实例解析

    PYTHON与C相互交互调用实例解析 使用前工具: Vc++编译器 Python解释器 如没有装VC,可以去微软网站下一个C++的编译器,地址如下: 装完后,在环境变量中把PYTHON的INCLUDE ...

  2. python交互模式切换_Python 交互式窗口 (REPL) - Visual Studio | Microsoft Docs

    使用 Python 交互窗口Work with the Python Interactive window 02/11/2019 本文内容 Visual Studio 为每个 Python 环境提供交 ...

  3. python代码命令行tab补齐_Python语言交互模式下命令tab补全

    本文主要向大家介绍了Python语言交互模式下命令tab补全,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助. python默认就可以进行tab补全命令行,在交互模式下,只要自己写个 ...

  4. python交互数据_Python用户交互以及数据类型

    一.用户交互与格式化输出 1.用户交互 1.1什么是用户交互 程序等待用户输入的数据,程序执行完毕后为用户反馈信息. 1.2为何程序要与用户交互 为了让计算机像人类一样与用户交互 1.3使用方式 在p ...

  5. python语音转文字_Python文字转语音示例

    python语音转文字 Here you will get python text to speech example. 在这里,您将获得python文本语音转换示例. As we know, som ...

  6. python中文字符串转语音_Python实现文字转语音功能

    知乎第一篇文章,本来想写一篇简单的单进程单线程爬虫教程的,可是知乎上这样的文章已经有很多了,而且写的好的挺多,我就不添堵了.下次有空的话写一篇多线程请求的爬虫教程. 这是一篇简单的Python文字(汉 ...

  7. python实现文字转语音_Python 文字转语音

    利用Python将文字转为语音播放 挺简单的代码,几分钟就可以做好,下面介绍一下 首先,安装pyttsx3依赖包,很简单 win+R 打开运行,输入 cmd 回车,进入控制台,键入以下代码: pip ...

  8. python什么模块动态调用链接库_Python调用C/C++动态链接库的方法详解

    本文以实例讲解了Python调用C/C++ DLL动态链接库的方法,具体示例如下: 示例一: 首先,在创建一个DLL工程(本例创建环境为VS 2005),头文件: 1 2 3 4 5 6 7 8 9 ...

  9. python是c语言_python与c语言

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! python语言调用c语言进行扩展,或者增加程序的运行速度都是特别方便的. 同时 ...

最新文章

  1. 朴素贝叶斯python实现预测_Python实现朴素贝叶斯分类器的方法详解
  2. MySql中把一个表的数据插入到另一个表中的实现代码--转
  3. 基于迁移学习的反欺诈方法研究
  4. Maven项目中引入spring-test单元测试 @RunWith与@ContextConfigration报错
  5. 超棒的Glide图片加载
  6. OPPO F11 Pro渲染图曝光:升降式前置摄像头设计
  7. python write函数换行_Python基础知识(三)
  8. php版给UEditor的图片在线管理栏目增加图片删除功能
  9. a3图纸标题栏尺寸标准_标准CAD制图上A3图幅上的标题栏尺寸是多少
  10. 变编程用户输入月份,判断这个月份是属于哪个季节?
  11. 在win7系统下使用TortoiseGit(乌龟git)简单操作Git@OSC
  12. GCC学习(动态库与静态库.a与.so)
  13. ireport 5.6.0 添加 Conditional Style 动态加粗字体
  14. Material Design学习总结
  15. css 实现三维立体旋转效果
  16. springboot-grpc
  17. 自动修复工具介绍——SemFix [ICSE 2013]
  18. GDB调试之定位段错误
  19. 解读《电信重组公告》:3G发牌仍然无期限
  20. 抖音小店无货源是怎么做的?开店需要我们准备什么?经验分享

热门文章

  1. Java 数组排序及元素查找
  2. ndows10同时打印多份文档,Windows10如何同时重命名多个文件
  3. 文件后缀_电脑文件名的后缀即扩展名的显示和隐藏方法
  4. 【OpenCV 例程200篇】72. 一维离散傅里叶变换
  5. Python小白的数学建模课-15.图论的基本概念
  6. java合并sheet行_java poi Excel循环合并行
  7. linux内核编译的image,内核编译时生成uImage的办法
  8. python write报错a byte-like object is required.not str
  9. c语言中文刷屏,c语言二维数组刷屏练习.doc
  10. 【Python】PyCryptodome模块实现多种加密算法