zoukankan      html  css  js  c++  java
  • Python 使用ctypes调用 C 函数

    在python中通过ctypes可以直接调用c的函数,非常简单易用

    下面就一步一步解释用法吧,以Linux为例讲解。

    1, 首先确定你的python支持不支持ctypes 

    python2.7以后ctypes已经是标配了,2.4以后的版本得自己装下ctypes

    2,加载动态库 

         两种加载方式

         >>> from ctypes import *
         >>> libc = cdll . LoadLibrary ( "libc.so.6" )
         >>> libc.printf("%d",2)
         >>> from ctypes import *
         >>> libc = CDLL ( "libc.so.6" )
         >>> libc.printf("%d",2) 

    3, 调用系统函数 

       上面的例子已经调用了系统函数printf,这里再给几个其他例子

         >>> from ctypes import *
         >>> libc = CDLL ( "libc.so.6" )
         >>> print libc . time ( None )
         1308019893
         >>> print libc.atoi("234")
         234 

    4,ctypes 数据类型和 C数据类型 对照表 

    ctypes typeC typePython type
    c_bool _Bool bool (1)
    c_char char 1-character string
    c_wchar wchar_t 1-character unicode string
    c_byte char int/long
    c_ubyte unsigned char int/long
    c_short short int/long
    c_ushort unsigned short int/long
    c_int int int/long
    c_uint unsigned int int/long
    c_long long int/long
    c_ulong unsigned long int/long
    c_longlong __int64 or long long int/long
    c_ulonglong unsigned __int64 or unsigned long long int/long
    c_float float float
    c_double double float
    c_longdouble long double float
    c_char_p char (NUL terminated) string or None
    c_wchar_p wchar_t (NUL terminated) unicode or None
    c_void_p void * int/long or None



    这些数据都可以用一个默认值进行创建

    >>> c_int()
    c_long(0)
    >>> c_char_p("Hello, World")
    c_char_p('Hello, World')
    >>> c_ushort(-3)
    c_ushort(65533)
    >>> 

    这些数据也可以被改变:

    >>> i = c_int(42)
    >>> print i
    c_long(42)
    >>> print i.value
    42
    >>> i.value = -99
    >>> print i.value
    -99
    >>> 

    赋值给 c_char_p,c_wchar_p,c_void_p 

    只改变他们指向的内存地址,而不是改变内存的内容


    >>> s = "Hello, World"
    >>> c_s = c_char_p(s)
    >>> print c_s
    c_char_p('Hello, World')
    >>> c_s.value = "Hi, there"
    >>> print c_s
    c_char_p('Hi, there')
    >>> print s                 # first string is unchanged
    Hello, World
    >>> 

    如果需要可改变内容的字符串,需要使用 create_string_buffer()


    >>> from ctypes import *
    >>> p = create_string_buffer(3)      # create a 3 byte buffer, initialized to NUL bytes
    >>> print sizeof(p), repr(p.raw)
    3 '/x00/x00/x00'
    >>> p = create_string_buffer("Hello")      # create a buffer containing a NUL terminated string
    >>> print sizeof(p), repr(p.raw)
    6 'Hello/x00'
    >>> print repr(p.value)
    'Hello'
    >>> p = create_string_buffer("Hello", 10)  # create a 10 byte buffer
    >>> print sizeof(p), repr(p.raw)
    10 'Hello/x00/x00/x00/x00/x00'
    >>> p.value = "Hi"
    >>> print sizeof(p), repr(p.raw)
    10 'Hi/x00lo/x00/x00/x00/x00/x00'
    >>> 

    5,函数返回类型 

    函数默认返回 C int 类型,如果需要返回其他类型,需要设置函数的 restype 属性

    >>> strchr = libc.strchr
    >>> strchr("abcdef", ord("d")) # doctest: +SKIP
    8059983
    >>> strchr.restype = c_char_p # c_char_p is a pointer to a string
    >>> strchr("abcdef", ord("d"))
    'def'
    >>> print strchr("abcdef", ord("x"))
    None
    >>> 

    6,传递指针或者引用 

    很多情况下 C 函数需要传递指针或者引用,ctypes也完美的支持这一点
    byref() 用来传递引用参数,pointer() 函数也可以完成同样的工作,但pointer()会创建一个实际的指针对象,如果你不需要一个指针对象,
    用byref()会快很多

    >>> i = c_int()
    >>> f = c_float()
    >>> s = create_string_buffer('/000' * 32)
    >>> print i.value, f.value, repr(s.value)
    0 0.0 ''
    >>> libc.sscanf("1 3.14 Hello", "%d %f %s",... byref(i), byref(f), s)
    3
    >>> print i.value, f.value, repr(s.value)
    1 3.1400001049 'Hello'
    >>> 

    7,结构体和联合 
    结构体和联合必须从 Structure 和 Union 继承,子类必须定义 
    _fields_ 属性,_fields_ 属性必须是一个2元组的列表,
    包括一个field名字和field的类型
    field类型 必须是一个ctypes的类型例如 c_int, 或者其他继承自ctypes的类型,结构体,联合,数组,指针。

    下面的例子演示一个 POINT结构体,包括 field  X,Y

    >>> from ctypes import *
    >>> class POINT(Structure):. 
        _fields_ = [("x", c_int),
                    ("y", c_int)]

    >>> point = POINT(10, 20)
    >>> print point.x, point.y
    10 20
    >>> point = POINT(y=5)
    >>> print point.x, point.y
    0 5
    >>> POINT(1, 2, 3)
    Traceback (most recent call last):
      File "<stdin>", line 1
    , in ?
    ValueError
    : too many initializers
    >>> 

    一个复杂点的例子,field类型也是一个结构体

    >>> class RECT(Structure):
    ...     _fields_ = [("upperleft", POINT),
    ...                 ("lowerright", POINT)]
    ...
    >>> rc = RECT(point)
    >>> print rc.upperleft.x, rc.upperleft.y
    0 5
    >>> print rc.lowerright.x, rc.lowerright.y
    0 0
    >>> 

    多种方式进行初始化
    >>> r = RECT(POINT(1, 2), POINT(3, 4))
    >>> r = RECT((1, 2), (3, 4)) 

    8,数组 

    数组定义很简单

    定义一个有10个POINT元素的数组

    TenPointsArrayType = POINT * 10 

    初始化和使用数组:

    >>> from ctypes import *
    >>> TenIntegers = c_int * 10
    >>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    >>> print ii
    <c_long_Array_10 object at 0x...>
    >>> for i in ii: print i,
    ...
    1 2 3 4 5 6 7 8 9 10
    >>> 


    9,指针 
    pointer() 函数可以创建一个指针

    Pointer实例有一个 contents属性 返回指针指向的对象

    >>> from ctypes import *
    >>> i = c_int(42)
    >>> pi = pointer(i)
    >>> pi.contents
    c_long(42) 

    可以改变指针指向的内容

    >>> i = c_int(99)
    >>> pi.contents = i
    >>> pi.contents
    c_long(99)
    >>> 

    可以按数组方式访问:

    >>> pi[0]
    99
    >>> 

    按数组方式改变值
    >>> print i
    c_long(99)
    >>> pi[0] = 22
    >>> print i
    c_long(22)
    >>> 

    以上都是ctypes的基本用法,对普通的开发人员来说,基本够用了

    更详细的说明请参考:http://docs.python.org/library/ctypes.html

  • 相关阅读:
    C# 读写ini文件
    How to Create DLL(Dynamic link library)
    运算符优先级
    汇编指令:lea
    AT&T汇编语法与x86语法基本区别
    栈的生长方向理解
    Mac Mojave 10.14.5安装python tesserocr
    一台电脑发布多个网站
    局域网内电脑之间互相访问网站
    判断两个对象是否相等——javascript实现
  • 原文地址:https://www.cnblogs.com/yanzi-meng/p/8066947.html
Copyright © 2011-2022 走看看