python高级ctypes数据类型—结构体

结构体在ctypes中通过类进行定义。用于定义结构体的类需要继承自ctypes的Structure基类,而后通过定义类的_fields_属性来定义结构体的构成。_fields_属性一般定义为一个二维的tuple,而对于其中的每一个一维tuple,其需要定义两个值,第一个值为一个字符串,用作结构体内部的变量名,第二个值为一个ctypes类型,用于定义当前结构体变量所定义的数据类型。注意,在Python中定义的结构体,其变量名,类名等均可以不同于C语言中的变量名,但结构体变量的数量、数据类型与顺序必须严格对应于C源码中的定义,否则可能将导致内存访问出错。例:

import ctypes
Class TestStruct(Struct):
	_fields_ = [
	                 ('x',c_int),
	                 ('y',c_double)
	                 ]

以上代码即定义了一个结构体类型,其等同于C中的struct声明。此结构体定义了两个结构体变量:x对应于一个int类型,y对应于一个double类型。
结构体类型可以通过实例化得到一个结构对象,在实例化的同时也可传入初始化参数,作为结构变量的值。在得到结构对象后,也可通过点号访问结构体成员变量,从而对其赋值。例:

testStruct = TestStruct(1, 2)
print(testStruct.x, testStruct.y)
testStruct.x, testStruct.y = 10, 20
print(testStruct.x, testStruct.y)

上述代码通过实例化TestStruct类,并为其提供初始化参数,得到了一个结构体实例,第一次输出结果即为1 2.0。而后,再通过属性访问的方式修改了结构体中的两个变量,则第二次输出结果为10 20.0。
上面定义的结构体可直接传入C代码中,且上文已经提到,两边定义的结构体变量的各种名称均可不同,但数据类型、数量与顺序必须一致。例:

struct TestStruct
{   
	int 	a;   
	double b;
}
extern "C"
{
	void printStruct(TestStruct testStruct);
}
void printStruct(TestStruct testStruct)
{   
	printf("%d %f\n", testStruct.a, testStruct.b);
}

Python部分:

dllObj = CDLL('1.dll')
class TestStruct(Structure):  
	 _fields_ = (
	 			('x', c_int),       
	 			('y', c_double),    
	 		  )
testStruct = TestStruct(1, 2)
dllObj.printStruct(testStruct)

由此可见,在Python中实例化得到的结构体实例,可以直接当做C中的结构体实参传入。结构体也可以指针的方式传入,通过上节介绍的byref或者pointer函数即可实现转化。同样的,这两个函数都可直接接受结构体实例作为参数进行转化,byref返回简单指针,而pointer返回指针对象,可访问其contents属性得到指针所指向的值。例:C部分,上述printStruct函数修改为接受结构体指针的版本:

void printStruct(TestStruct *testStruct)
{   
	printf("%d %f\n", testStruct -> a, testStruct -> b);
}

Python部分:

testStruct = TestStruct(1, 2)
dllObj.printStruct(byref(testStruct))

上述代码将结构体对象testStruct作为byref的参数,从而将其转换为指针传入printStruct函数中。又例:

testStruct = pointer(TestStruct(1, 2))
dllObj.printStruct(testStruct)
print(testStruct.contents.x,testStruct.contents.y)

上述代码通过结构体对象生成了一个指针类型,并将此指针传入函数,可达到同样的效果。且在Python内部,结构体指针类型可以访问其contents属性,得到指针所指向的结构体,然后可继续访问结构体的x与y属性,得到结构体中保存的值。

你可能感兴趣的:(Python)