python 中如何使用 C 类型的数组? ctypes 的用法

导入C类型库

1
from ctypes import *

常用的C类型

c_int、c_long、c_int32

– C 类型的long int,这两个类型完全相同。
– python用int与之相应,但c_int的取值范围是32 bit的整数 。
– 占用4字节内存

c_int64

– 64 bit 整数,占用 8 字节内存
– python 用 int 与之相应

c_double、c_float

– C 类型的double, 这两个名字( c_double、c_float 完全相同 )
– 占用 8 字节内存
– python 用 float 与之相应

c_byte

– C 类型的byte, python 用 int 与之相应
– 占用1字节内存

c_char

– C的8 bit字符型

c_wchar

– C的unicode字符

备注

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
ctypes模块

C类型 Python类型 ctypes 类型
char 1-character/string c_char
wchar_t 1-character/Unicode、string c_wchar
char int/long c_byte
char int/long c_ubyte
short int/long c_short
unsigned short int/long c_ushort
int int/long C_int
unsigned int int/long c_uint
long int/long c_long
unsigned long int/long c_ulong
long long int/long c_longlong
unsigned long long int/long c_ulonglong
float float c_float
double float c_double
char *(NULL terminated) string or none c_char_p
wchar_t *(NULL terminated) unicode or none c_wchar_p
void * int/long or none c_void_p

当一个函数期望一个指针作为参数时,可以像这样调用
function_main( byref(parameter) ). //

struct例子
下面的例子是定义一个结构
C语言例子
struct beer_recipe
{
int amt_barley;
int amt_water;
};

Python例子
class beer_recipe(Structure):
_fields_ = [
("amt_barley", c_int),
("amt_water", c_int),
]


Union结构例子
C语言例子
union {
long barley_long;
int barley_int;
char barley_char[8];
}barley_amount;

Python例子
class barley_amount(Union):
_fields_ = [
("barley_long", c_long),
("barley_int", c_int),
("barley_char", c_char * 8),
]

生成类似C的数组

python原生数组list

1
2
3
4
5
a = [ 0 ] * 10
for i in range(0, len(a)):
print( a[i], end=" ")

输出:0 0 0 0 0 0 0 0 0 0

生成10元素的c_int类型的数组

格式一:

1
2
3
4
5
 from ctypes import *
a = ( c_int * 10) ()
for i in range(0, len(a)):
print( a[i], end=" ")
输出:0 0 0 0 0 0 0 0 0 0

格式二:

1
2
3
4
5
6
from ctypes import *
myArr10 = c_int * 10
a = myArr10()
for i in range(0, len(a)):
print( a[i], end=" ")
输出:0 0 0 0 0 0 0 0 0 0

c_double 的数组定义与上面相似

如何使用 C 类型的数组

对整数数组倒序的程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#coding=gbk
from ctypes import *
# 定义 具有10个 c_int 元素的数组
# 编写一维数组的 倒序的程序
# 说明 : 本算法参照 网上基于指针的算法改写而成。
def outPut( A ):
for i in range(0,N):
print( A[i], end=" ")
print ( "\n")

def arrReverse( A , N):
i = 0 ; j = N-1
while i<j:
A[i], A[j] = A[j], A[i]
# 相当于 T =A[i]; A[i]=A[j]; A[j]=T
i = i+1; j=j-1

#测试程序
N = 10
a = (c_int * N )()
for i in range(0,N):
a[i] = i;
print ( "原数组:")
outPut( a )
arrReverse( a ,len(a) )
print ("倒序数组:")
outPut( a )


--- 结果 ---


原数组:
0 1 2 3 4 5 6 7 8 9


倒序数组:
9 8 7 6 5 4 3 2 1 0

求倒序字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#coding=gbk
from ctypes import *
# 编写求字符串的倒序字符串
def arrReverse( A , N ):
i = 0 ; j = N-1
while i<j:
A[i], A[j] = A[j], A[i]
# 相当于 T =A[i]; A[i]=A[j]; A[j]=T
i = i+1; j=j-1

#测试程序

a = create_unicode_buffer( "张三买了一头小毛驴,花了1024.05元钱。")

print ( "原字符:")
print ( a.value )
arrReverse( a , len( a ) -1 )
print ("倒序字符串:")
print ( a.value )

-- 结果 --

原字符:
张三买了一头小毛驴,花了1024.05元钱。
倒序字符串:
。钱元50.4201了花,驴毛小头一了买三张

解说

(1) create_unicode_buffer( python的字符串 )

是创建一个 c_wchar 的数组,其长度是 字符串的长度 +1 , 因为 C 的字符串是以 NULL 结尾的所以要多出一个元素才行。

c_wchar 是 unicode 字符。

(2) 如果您想创建一个可以装行下 100 个 unicode 字符 的空的C_wchar 数组:

ar = create_unicode_buffer( 100+1 )

此时, ar 具有 101 个元素,但只能装 100个字符。

由于 ar 是一个真正的数组,我们可以对它的每个元素(字符)进行修改。

从 ar 中取出 python 的字符串:

s = ar.value

s 中存放的是 ar 中保存的 unicode 字符相应的字符串

向 ar 中存于字符串

ar.value = "要存入的字符串"

但要注意:

您向 ar 中存入的字符串的字符个数必须小于等于 len(ar) -1

(3) 如果您知道 ar 中第 i 个元素的 字符编码,请使用 ord( ar[i] ) .

(4) 如果您想使 ar 的第 i 个元素 变为 "好" 这个字符,有两种方法:

ar[i] = "好"

或者

ar[i] = chr(22909)

因为 , "好" 的 uncode 编码是 22909。

小结

– 从这个程序我们看到 对整数数组及 unicode 字符数组 的倒序,我们用的是相同的arrReverse 函数。

– 调用 arrReverse 函数时,传递元素个数 N 时,如果是 c_wchar ( unicode ) 字符数组时, 如记住最后一个元素是 NULL 这个问题。

– 您会发现,我们这里编的程序很像 C 语言的指针,只不过,我们不需要手工释放动态申请的数组。

– 但是您的算法中若用了大量的动态数组,等不及垃圾自动回收,而急于想释放数组占用的空间时,请使用 del ( ar )即可。

– 最后一点: C 语言关于字符串的操作,常 使用指针的移动, 我们在 python 中移动的是数组的下标,这是作程序移植时常用的方法。

C类型的数组 与 python 的 list 用法上有什么区别和联系呢?

– C 类型的数组的长度是不可变 的。

– C 类型数组的元素是可变的,即可以读写的

– C 类型数组的元素是有类型的,即: 它的每个元素的类型是相同的, 而 python 的 list 的元素可以是相同类型,也可以是不同类型 。

– C 类型数组除了不能用 形如 ar[ 3:5 ] = [] 格式的语句来删除某个子数组

– C 类型数组的切片:
如 x = ar[3:5]

此时 x 是一个全新的 数组,它是原数组的完全拷贝, 此时 x 有两个元素:

x[0] 中存的是 ar[3]的值

x[1] 中存的是 ar[4]的值

此后,改变 x[0] 时, ar[3] 不会改变; 改变 ar[3] 的值,也不会改变 x[0] 的值。