• 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

  • 相关阅读:
    Springboot 之 自定义配置文件及读取配置文件
    SQLSERVER系统视图 sql server系统表详细说明
    MySQL Workbench建表时 PK NN UQ BIN UN ZF AI 的含义
    使用Ecplise git commit时出现"There are no stages files"
    maven添加sqlserver的jdbc驱动包
    java将XML文档转换成json格式数据
    java将XML文档转换成json格式数据
    cannot be resolved. It is indirectly referenced from required .class files
    org.codehaus.jackson.map.JsonMappingException: Can not construct instance of java.util.Date from String value '2012-12-12 12:01:01': not a valid representation (error: Can not parse date "2012-12-
    @Autowired注解和静态方法 NoClassDefFoundError could not initialize class 静态类
  • 原文地址:https://www.cnblogs.com/yanzi-meng/p/8066947.html
Copyright © 2020-2023  润新知