日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

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

發布時間:2025/3/15 python 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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.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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。