您的位置:首页 > 编程语言 > Python开发

python中使用 C 类型的数组以及ctypes 的用法

2017-10-19 17:54 246 查看
Python 在 ctypes 中为我们提供了类似C语言的数据类型,
它的用途(我理解的)可能是:
(1) 与 其他语言(如 C、Delphi 等)写的动态连接库DLL 进行交换数据,因为 python 的 数据与 DLL难以进行数据交换。
(2) python 的字符串一旦形成,是不可变的,为了算法的需要,我们有时需要对字符串进行原位操作 ( in place ),而不想浪费另外的内存空间。
(3) python 具有很简明的语法,人们乐于使用。在解决实际问题时,字符串的处理占据了很大的开发量。
     互联网上有很多有用的算法可以帮助我们解决问题,如果我们能用python 写类似于 C 语言的程序,就不需要用其他语去写扩展了。
     有人会问,既然如此,用C语言,不就好了吗?
      当然可作这种选择,在用 python 的优势在于:既用使用了C语言的优点,也使用了Python的最大优点: 垃圾自动回收,代码简洁等。
    
一、 导入 C 类型 库
from ctypes import *
二、 常用的C 类型
(1) c_int   、 c_long 、c_int32
      C 类型的long int ,这两个类型完全相同。
       python 用 int 与之相应 , 但c_int的取值范围是 32 bit 的整数 。
      占用 4 字节内存
   (2) c_int64
      64 bit 整数,占用 8 字节内存    , python 用 int 与之相应
   (2) c_double 、c_float
      C 类型的 double , 这两个名字( c_double 、c_float 完全相同 )
      占用 8 字节内存   
       python 用 float 与之相应
(3) c_byte
      C 类型 的 byte ,   python 用 int 与之相应
      占用1字节内存
   (4) c_char
       C 的 8 bit 字符型   
(5) c_wchar
      C 的 unicode 字符

【注】
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的数组
目的:初值化一个具有 10 个元素 的数组,每个元素初值为0的
   
(一) python 原生数组 list
>>>
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 类型的数组:

格式一:

>>> 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 

>>>

格式二:

>>> from ctypes import *

>>> M = 10

>>> a = ( c_int * M ) ()

>>> for i in range(0, len(a)):

    print( a[i], end=" ")

0 0 0 0 0 0 0 0 0 0

格式三:

>>> 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 , 对整数数组倒序的程序

#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

例2 求倒序字符串
#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。
小结:
(1) 从这个程序我们看到
对整数数组及 unicode 字符数组 的倒序,我们用的是相同的arrReverse 函数。
(2) 调用 arrReverse
函数时,传递元素个数 N 时,如果是 c_wchar ( unicode ) 字符数组时, 如记住最后一个元素是 NULL 这个问题。
( 3 ) 您会发现,我们这里编的程序很像 C 语言的指针,只不过,我们不需要手工释放动态申请的数组。
( 4 ) 但是您的算法中若用了大量的动态数组,等不及垃圾自动回收,而急于想释放数组占用的空间时,请使用
del ( ar )即可。

( 5) 最后一点:
     C 语言关于字符串的操作,常 使用指针的移动, 我们在 python 中移动的是数组的下标,这是作程序移植时常用的方法。
五、 C类型的数组 与 python 的 list 用法上有什么区别和联系呢?
1 C 类型的数组的长度是不可变 的。
2 C 类型数组的元素是可变的,即可以读写的
3 C 类型数组的元素是有类型的,即: 它的每个元素的类型是相同的, 而 python 的 list 的元素可以是相同类型,也可以是不同类型 。
4 C 类型数组除了不能用 形如 ar[ 3:5 ] = [] 格式的语句来删除某个子数组
5 C 类型数组的切片:
   如 x = ar[3:5]
   此时 x 是一个全新的 数组,它是原数组的完全拷贝, 此时 x 有两个元素:
   x[0] 中存的是 ar[3]的值
   x[1] 中存的是 ar[4]的值   
    此后,改变 x[0] 时, ar[3] 不会改变; 改变 ar[3] 的值,也不会改变 x[0] 的值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: