python中的ctypes庫初探

python ctypes

Table of Contents

1 Python中調用C語言庫

Python中提供了ctypes標準庫,用來調用C語言庫中的函數。

  1. 加載dll C語言函數存在不同的調用約定,常見的有stdcall和cdecl,這兩種調用約定在Python中的調用函數需要區分:
    • stdcall的加載方式: dll = windll.LoadLibrary("dllpath") dll = WinDLL("dllpath")
    • cdecl的加載方式: dll = cdll.LoadLibrary("dllpath") dll = CDLL("dllpath")
  2. 調用函數,傳入參,返回值 C函數通過參數讀取值,做處理後通過返回值傳回。
    #include <stdlib.h>
    // file add.c
    #include <stdio.h>
    
    int add(const int a, const int b)
    {
        return a+b;
    }
    
    

    把C函數編譯爲.so庫,執行一下命令: gcc -shared -fPIC -o libadd.so add.c

    from ctypes import *
    
    dll = CDLL("./libadd.so")
    
    print("add(1,2) = ", dll.add(1, 2))
    
    

    執行Python命令,查看執行情況: python3 ./add.py add(1,2) = 3

  3. C函數通過參數傳出值,即參數是指針的情況 C語言指針概念在ctypes中用pointer對應,如下示例:
    #include <stdlib.h>
    // file add.c
    #include <stdio.h>
    
    int add(const int a, const int b)
    {
        return a+b;
    }
    
    
    int add2(const int a, const int b, int *c)
    {
        if (NULL != c)
            *c = a+b;
    
        return a+b;
    }
    

    add2函數傳入指針,並可通過指針輸出值。 python調用函數如下:

    from ctypes import *
    
    dll = CDLL("./libadd.so")
    
    print("add(1,2) = ", dll.add(1, 2))
    
    out = c_int(0)
    ptr = pointer(out)
    
    out.value = 100
    print("out.value = ", out.value)
    dll.add2(2,3,ptr)
    print("add2(2, 3) = ", out.value)
    
    

    python3 ./add.py add(1,2) = 3 out.value = 100 add2(2, 3) = 5

  4. 參數是結構體指針 結構體通過繼承Structure類實現,各字段通過field定義,示例如下:
    typedef struct
    {
        int x;
        int y;
    } Point;
    
    
    int add3(const Point a, const Point b, Point *c)
    {
        if (NULL == c)
            return 255;
        c->x = a.x + b.x;
        c->y = a.y + b.y;
        return 0;
    }
    
    

    Python中的定義如下:

    class Point(Structure):
        _fields_ = ("x", c_int), ("y", c_int)
        def __repr__(self):
            return "(%d, %d)" % (self.x, self.y)
    
    p1 = Point(1,2)
    p2 = Point(5, 8)
    p3 = Point(0,0)
    ptr_p3 = pointer(p3)
    
    dll.add3(p1,p2,ptr_p3)
    print("add3(p1,p2) = ", p3)
    
    

    其中_repr_是python的內置函數,這個是類的展示函數,相當於java語言中的toString()函數。

  5. 入參char*指針
    int pr(const char *name, char *out)
    {
        printf("Hello, %s\n", name);
        sprintf(out, "Hello, %s\n", name);
        return 0;
    }
    
    
    • 方法1
      sbuf = create_string_buffer(b'robin')
      out  = create_string_buffer(100)
      dll.pr(sbuf, out)
      print("1--", out.value)
      
      
    • 方法2
      sbuf2 = b'\0'*10
      pStr = c_char_p()
      pStr.value = sbuf2
      dll.pr(b'John', pStr)
      print("2--", sbuf2)
      
      
    • 方法3
      sbuf3 = b'\0'*20
      dll.pr(b'Rich', sbuf3)
      print("3--", sbuf3)
      
      
  6. 字節序處理 fields定義的每個參數的類型後面可以定義bit位,示例如下:
    int swap32(const int x)
    {
        return htonl(x);
    }
    
    

    Python中測試字節序如下:

    class Int(Structure):
        _fields_ = [("uint8_0", c_int, 8),
                    ("uint8_1", c_int, 8),
                    ("uint8_2", c_int, 8),
                    ("uint8_3", c_int, 8)]
    
        def __init__(self, i):
            i0 = i & 0xFF
            i1 = (i >> 8) & 0xFF
            i2 = (i >> 16) & 0xFF
            i3 = (i >> 24) & 0xFF
            super().__init__(i0,i1,i2,i3)
    
        def __repr__(self):
            return "0x%08X" % ((self.uint8_3<<24) + \
                (self.uint8_2<<16) + \
                (self.uint8_1<<8) + \
                (self.uint8_0))
    
    
    i = Int(0x12345678)
    i_big = dll.swap32(i)
    print( i, "0x%08X" % i_big)
    
    

    這裏使用Int主要是爲了測試bit的定義,這個用例用Python內置的int類型ibig=dll.swap32(0x12345678)就可以。

Date: 2013-07-28 17:56:36 中國標準時間

Author:

Org version 7.8.11 with Emacs version 24

Validate XHTML 1.0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章