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

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.comzhihu-card-default.svg指针类型

指针数组类型

结构体指针类型

结构体指针数组类型

函数指针

类型转换

获取函数返回值类型

二.处理字节流

在使用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中每个数据的长度对字节流先进行切片,然后再进行大小端转换。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/573967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python3获取网页内容_python3获取一个网页特定内容

我们今天要爬取的网址为:https://www.zhiliti.com.cn/html/luoji/list7_1.html 一、目标:获取下图红色部分内容即获取所有的题目以及答案。 二、实现步骤。 分析: 1,首先查看该网站的结构。分析网页后可以得到: 我们需…

Linux64位steam,这下没得玩了! Steam无奈抛弃Linux用户

众所周知,Linux被公认为最安全的操作系统,近日,网络有消息传出Linux发行版Ubuntu确认将从今年下半年的19.10版本开始不再支持传统32位,而仅支持64位,而没有了32位系统的存在,许多游戏将不能支持。据了解&am…

解决问题:无法对 System程序集 添加Fakes程序集

为了在单元测试中指定DateTime.Now的值,我采用Microsoft Fakes技术的Shim。 主要参考了园里的http://www.cnblogs.com/FreeDong/p/3353111.html,编译时出了几千个警告,最终在“引用”中没有出现System.4.0.0.0.Fakes,当然了&#…

python抖音github_使用 Python 下载抖音无水印视频

抖音 APP 中保存到本地就是无水印版本的,所以头条的服务器肯定是保存有无水印版本的抖音视频的,所以只要找到接口地址就可以搞定。先在网上搜罗了一圈,确实有人已经做了解析,还提供了收费解析服务。 搜索之后发现又发现了同类型的…

linux 7 nano,Linux初學(CnetOS Linux7)之文本編輯器nano以及關機

1.nano文本編輯器[xiaohuilocalhost ~]$nano text.txt# 不管text.txt存不存在都沒有關系&#xff01;存在就開啟舊檔&#xff0c;不存在就開啟新檔GNU nano 2.3.1 File: text.txt<這個是游標所在處[ New File ]^G Get Help ^O WriteOut ^R Read File ^Y Prev Page ^K Cut Te…

grep 和 sed:linux经常使用工具 amp; 基本正則表達式

grep 见链接&#xff1a;http://www.cyberciti.biz/faq/grep-regular-expressions/ sed參考文章&#xff1a;http://www.thegeekstuff.com sed工作原理 This is called as one execution cycle. Cycle continues till end of file/input is reached&#xff1a; 1. Read a ent…

远程主机http协议版本信息泄漏_Web基础之http协议

Http协议介绍&#xfffc;HTTP 全称&#xff1a;Hyper Text Transfer Protocol 中文名&#xff1a;超文本传输协议什么是超文本包含有超链接(Link)和各种多媒体元素标记(Markup)的文本。这些超文本文件彼此链接&#xff0c;形成网状(Web)&#xff0c;因此又被称为网页(Web Page…

c语言opengles程序,OpenGL ES _ 着色器_程序

演示图你不知道这个东西&#xff0c;请不要看了,请看我的其他文章先了解一下O!学习目标掌握着色器程序的执行过程简单的例子uniform float t; // 时间uniform mat4 gl_ModelViewMatrix; // 模型视图矩阵attribute vec4 vel;const vec4 g vec4(0.0,-9.8,0.0) // 重力加速度void…

spring IOC加载流程

看了网上、书上很多对于spring IOC容器加载过程的分析。大多都只是粗略的讲一下加载流程。其实这样也不错&#xff0c;简单粗暴。清晰记得之前和一个前辈交流时他说的一句话&#xff1a;什么设计模式、设计框架都是扯淡&#xff0c;能实现这个功能就是最好的。其实这样的说法是…

pytorch 模型可视化_【深度学习】高效使用Pytorch的6个技巧:为你的训练Pipeline提供强大动力...

作者&#xff1a;Eugene Khvedchenya 编译&#xff1a;ronghuaiyang导读只报告模型的Top-1准确率往往是不够的。将train.py脚本转换为具有一些附加特性的强大pipeline每一个深度学习项目的最终目标都是为产品带来价值。当然&#xff0c;我们想要最好的模型。什么是“最好的”…

c语言 %-20s,一次 Rust 和C语言的混搭

存在内存泄露extern crate libc;use libc::size_t;use libc::{FILE,c_char};use std::string;#[repr(C)]pub struct mntent {mnt_fsname :*mut c_char, /* 挂载的文件系统的名字 */mnt_dir :*mut c_char, /* 挂载点 */mnt_type :*mut c_char, /* 文件系统类型&#xff1a;ufs、…

KMP算法———模板

做出KMP字符串匹配算法心情也是好好哒&#xff0c;萌萌哒。 感谢黄学长&#xff0c;感谢栋栋&#xff01; #include<cstdio>#include<string>#include<iostream>using namespace std;int p[101];int main(){ string a,b; cin>>a>>b; int na.leng…

tstringlist怎么查看是否存在该数据_注意!研究生招生信息只公开1个月!应该怎么用?...

请注意&#xff01;全国硕士研究生招生信息公开平台&#xff08;以下简称“研招信息公开平台”&#xff09;已于2019年7月1日开放-2019年7月30日结束。招生信息怎么看&#xff1f;老师在线教你看懂研究生招生信息&#xff01;本篇目录&#xff1a;1.全国硕士研究生招生信息公开…

山东外贸职业学院王彩霞老师网上考试系统及c语言考试题库》,2015年山东外贸职业学院单招考试内容...

测试方式及内容1、夏季高考考生&#xff1a;文化考试、基本技能测试、面试(总分400分)(1)文化考试&#xff1a;考试形式为笔试&#xff0c;考试科目&#xff1a;语文、数学。两科一套卷子&#xff0c;分值为&#xff1a;语文100分、数学100分&#xff0c;总分200分&#xff0c;…

5.UiScrollable API 详细介绍

Tip&#xff1a; 1.扫动过程中如果界面停留在滚动条的中间部分会先回到起点再进行滚动 2.扫动过程中设置的步长长短决定划过内容的多少&#xff0c;步长越长滑过的内容就越少&#xff1b;步长越短划过的内容就越长 一、UiScrollable 类介绍 1.UiScrollable类说明 1&#xff09;…

delphi读取xml中的内容property name传递参数_Python 进阶知识全篇-XML 解析

什么是 XML&#xff1f;XML 指可扩展标记语言&#xff08;eXtensible Markup Language&#xff09;&#xff0c;标准通用标记语言的子集&#xff0c;是一种用于标记电子文件使其具有结构性的标记语言。 你可以通过本站学习 XML 教程XML 被设计用来传输和存储数据。XML 是一套定…

c语言getline读取一行命令行,如何从文件的特定行中获取getline()? C ++

这个问题非常不清楚。您如何确定具体线&#xff1f;如果是第n行&#xff0c;最简单的解决方案就是调用getlinen次&#xff0c;扔掉除最后一个结果以外的所有结果&#xff1b;呼唤ignoren-1次可能会快一点&#xff0c;但我怀疑如果您总是读入相同的字符串(而不是构造一个每次都更…

12.UiAutomator 获取系统信息

一、Build构建信息 1.build类&#xff1a; Build类提供了硬件厂商、编号、序列号、SDK版本等重要信息。 类名&#xff1a;android.os.Build 常量名 说明 BOARD底层板名称BOOTLOADERBootloader版本号BRAND品牌CPU_ABICPU指令集CPU_ABI2CPU第二指令集DEVICE工业设计名称DISPLAY显…

c语言编写网页图形界面代码,「分享」C语言如何编写图形界面

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼贴吧内经常有人问C语言是不是只能用于字符终端界面开发&#xff0c;不能用于图形界面。大家也都有回答&#xff0c;需要其他的库。MFC&#xff0c;GTK&#xff0c;QT。本人近期刚用GTK库加上纯C写成了第一个LINUX实用程序。现在与大…

python 读取word_教你怎么使用 Python 对 word文档 进行操作

使用Python对word文档进行操作一、安装Python-docxPython-docx是专门针对于word文档的一个模块&#xff0c;只能读取docx 不能读取doc文件。说白了&#xff0c;python就相当于windows操作系统&#xff0c;QQ就是跑在windows操作系统上的软件&#xff0c;QQ最大的作用是可以去聊…