應(yīng)該是史上最全的python調(diào)用C接口

這段時間需要用python調(diào)用C的接口催什,網(wǎng)上搜了很多涵亏,結(jié)合python的官方文檔,整理下備用
1蒲凶、加載dll

from ctypes import *
dll = cdll.LoadLibrary('DLL1.dll')#func1
dll = CDLL('DLL1.dll')#func2
print(dll)

2气筋、數(shù)據(jù)類型的對應(yīng)


3、函數(shù)調(diào)用
C

DLL1_API int fnDLL1(void)
{
    return 42;
}

Python

print(dll.fnDLL1())

4旋圆、參數(shù)傳遞
C

DLL1_API int fnDLL2(int a, float b, double c, const char * buffer,int &d)
{
    printf("recv : %d,%f,%f,%s,\n", a, b, c, buffer);
    d = 10;
    return 1;
}

int double float 這些類型可以直接傳遞
char * 直接傳遞bytes
指針或者引用類型需要用byref或者pointer宠默,也可以用相應(yīng)類型的指針類型
例如上個接口中傳遞 int &d 在傳遞的過程中可以用 byref(temp)

Python

    temp = c_int(0)
    print(dll.fnDLL2(1,c_float(2.0),c_double(3.0),'hell0'.encode('gbk'),byref(temp)))
    print('byref',temp1.value)

也可以用int的指針類型,這個類型需要自己定義灵巧,POINTER一般針對類型
而pointer針對實例化以后的對象搀矫,比如上面也可以用pointer(temp)

   type_p_int = POINTER(c_int)
    temp = type_p_int(c_int(0))
    print(dll.fnDLL2(1,c_float(2.0),c_double(3.0),'hell0'.encode('gbk'),temp))
    print('int *',temp,temp[0],temp.contents)

返回值
int,float,double 這些類型直接接收就可以
其他類型需要先設(shè)置接口的返回類型
C

DLL1_API char * fnDLL3(char *buf)
{
    return buf;
}

python

    dll.fnDLL3.restype = c_char_p
    res = dll.fnDLL3('hello'.encode('gbk'))
    print(res,type(res))

如果傳遞的是char * 需要改變其內(nèi)容抹沪,需要預(yù)先定義好存儲空間
C

DLL1_API int fnDLL4(char *buf, size_t buffsize)
{
    printf("%s\n", buf);
    memset(buf, 0, buffsize);
    sprintf(buf, "world");
    return 1;
}

python

    buf = create_string_buffer('hello'.encode('gbk'),10)
    dll.fnDLL4(byref(buf),10)
    print(buf.value)

unicode類型
C

DLL1_API WCHAR * fnDLL10(WCHAR * buf,size_t bufsize)
{
    wprintf(L"wchar:%s\n", buf);
    wmemset(buf, 0, bufsize);
    wsprintf(buf, L"hello world\n");
    return buf;
}

python

    wbuf = create_unicode_buffer("hello",32)
    dll.fnDLL10.restype = c_wchar_p
    res = dll.fnDLL10(byref(wbuf),32)
    print("wchar--",res)

5、結(jié)構(gòu)體定義
我們用 fields = [(‘name1’,type1),(‘name2’,type2)]來表示結(jié)構(gòu)體的成員
字節(jié)對齊 C結(jié)構(gòu)體中經(jīng)常會出現(xiàn)按照指定的字節(jié)進行對齊結(jié)構(gòu)體瓤球,用pack來指定對齊的字節(jié)數(shù)融欧,數(shù)組的定義直接用 *num 表示個數(shù)
C

#pragma pack(1)
struct MyStruct
{
    int a;
    double b;
    char c[32];
};
#pragma pack()

python

class MyStruct(Structure):
    _fields_ = [
        ('a',c_int),
        ('b',c_double),
        ('c',c_char*32),
    ]
    _pack_ = 1

位域
C

struct MyStruct1
{
    int a : 16;
    int b : 16;
};

python

class MyStruct1(Structure):
    _fields_ = [
        ('a',c_int,16),
        ('b', c_int, 16),
    ]

結(jié)構(gòu)體的嵌套
c

struct MyStruct2
{
    int a;
    MyStruct S[4];
};

python

class MyStruct2(Structure):
    _fields_ = [
        ('a',c_int),
        ('struct',MyStruct*4)
    ]

傳遞結(jié)構(gòu)體,與之前傳遞參數(shù)一樣卦羡,指針類型用byref或者pointer
c

DLL1_API int fnDLL5(MyStruct & s)
{
    printf("mystruct:\na:%d\nb:%f\nc:%s\n", s.a, s.b, s.c);
    return 1;
}

python

    mystruct = MyStruct()
    mystruct.a = 1
    mystruct.b = 1.0
    mystruct.c = 'helloworld'.encode('gbk')
    dll.fnDLL5(byref(mystruct))
    dll.fnDLL5(pointer(mystruct))

返回結(jié)構(gòu)體噪馏,與之前相同,需要指定返回的類型
c

DLL1_API MyStruct fnDLL6()
{
    MyStruct *tem = new MyStruct;
    tem->a = 10;
    tem->b = 20;
    sprintf(tem->c, "hello");
    return *tem;
}

python

    dll.fnDLL6.restype = MyStruct
    res = dll.fnDLL6()
    print(res)
    print('mystruct:', res.a, res.b, res.c)
    del res

高階數(shù)組的定義
int my_array[10][10];

    # 先定義一個數(shù)組類型
    type_int_array_10 = c_int * 10
    # 定義數(shù)組的數(shù)組(即二維數(shù)組)
    type_int_array_10_10 = type_int_array_10 * 10
    # 創(chuàng)建二維數(shù)組對象
    my_array = type_int_array_10_10()
    # 使用二維數(shù)組
    my_array[1][2] = 3

字節(jié)流與結(jié)構(gòu)體的相互轉(zhuǎn)換

#pack
    print(string_at(addressof(mystruct),sizeof(mystruct)))
#unpack
    buf = bytes(sizeof(MyStruct))
    assert len(buf)
    buf = create_string_buffer(sizeof(MyStruct))
    res = cast(pointer(buf),POINTER(MyStruct)).contents
    print(res,type(res))
    print('mystruct:',res.a,res.b,res.c)
def Pack(ctype_instance):   
    return string_at(addressof(ctype_instance),sizeof(ctype_instance))
def UnPack(ctype,buf):
    assert sizeof(ctype) == len(buf)
    cstring = create_string_buffer(buf)
    return cast(pointer(cstring),POINTER(ctype)).contents

回調(diào)函數(shù)
先用CFUNCTYPE 定義回調(diào)函數(shù)類型绿饵,參數(shù)的第一個參數(shù)為返回值類型
后面的參數(shù)為回調(diào)函數(shù)傳遞的參數(shù)類型欠肾,然后定義python中的函數(shù),
C

typedef int (*callbakc) (int a, int b);
DLL1_API void fnDLL7(int a, int b, callbakc func)
{
    int n = func(a, b);
    printf("c++ callback %d\n", n);
}

python

    CMPFUNC = CFUNCTYPE(c_int,c_int,c_int)
    cmp_func = CMPFUNC(callFunc)
    dll.fnDLL7(1,2,cmp_func)

這里有個地方特別注意蝴罪,如果回調(diào)函數(shù)中有void* 董济,char等類型,在python中定義回調(diào)函數(shù)的時候如果定義為 c_void_p ,c_char_p要门,實際返回的數(shù)據(jù)為int虏肾,bytes
這時候其實python內(nèi)部已經(jīng)把參數(shù)的值拿出來了,而我們需要的是char
地址的內(nèi)容欢搜,常用的比如傳遞某一串字節(jié)流封豪,我們需要傳遞出字節(jié)流的長度和首地址的指針,如果直接使用參數(shù),c_void_p拿到的是一個int類型炒瘟,而c_char_p拿到的是截止到最后一個'\0'的字節(jié)吹埠,最終我們在python中用string_at 來拿到實際的字節(jié)流
c回調(diào)

typedef void (*callbakc) (void * buf, int &buf_size);

python中的定義

def callback(buf,size):
    string = string_at(buf,size.value)

CALLBACKFUNC = CFUNCTYPE(None,c_void_p,c_int)
call = CALLBACKFUNC(callback)

OK,應(yīng)該基本都講到了疮装,后續(xù)有遇到的坑再繼續(xù)填

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缘琅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子廓推,更是在濱河造成了極大的恐慌刷袍,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件樊展,死亡現(xiàn)場離奇詭異呻纹,居然都是意外死亡,警方通過查閱死者的電腦和手機专缠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門雷酪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人涝婉,你說我怎么就攤上這事哥力。” “怎么了墩弯?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵吩跋,是天一觀的道長蟀淮。 經(jīng)常有香客問我,道長钞澳,這世上最難降的妖魔是什么怠惶? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮轧粟,結(jié)果婚禮上策治,老公的妹妹穿的比我還像新娘。我一直安慰自己兰吟,他們只是感情好通惫,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著混蔼,像睡著了一般履腋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惭嚣,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天遵湖,我揣著相機與錄音,去河邊找鬼晚吞。 笑死延旧,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的槽地。 我是一名探鬼主播迁沫,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼捌蚊!你這毒婦竟也來了集畅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤缅糟,失蹤者是張志新(化名)和其女友劉穎挺智,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溺拱,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡逃贝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年谣辞,在試婚紗的時候發(fā)現(xiàn)自己被綠了迫摔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡泥从,死狀恐怖句占,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情躯嫉,我是刑警寧澤纱烘,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布杨拐,位于F島的核電站,受9級特大地震影響擂啥,放射性物質(zhì)發(fā)生泄漏哄陶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一哺壶、第九天 我趴在偏房一處隱蔽的房頂上張望屋吨。 院中可真熱鬧,春花似錦山宾、人聲如沸至扰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敢课。三九已至,卻和暖如春绷杜,著一層夾襖步出監(jiān)牢的瞬間直秆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工鞭盟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留切厘,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓懊缺,卻偏偏與公主長得像疫稿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鹃两,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容