Python調(diào)用C語(yǔ)言動(dòng)態(tài)庫(kù)的方法小結(jié)
ctypes 是 Python 的外部函數(shù)庫(kù)。它提供了與 C 兼容的數(shù)據(jù)類(lèi)型,并允許調(diào)用 DLL 或共享庫(kù)中的函數(shù)。可使用該模塊以純 Python 形式對(duì)這些庫(kù)進(jìn)行封裝。
基本數(shù)據(jù)類(lèi)型對(duì)應(yīng)關(guān)系
[ctypes] 定義了一些和C兼容的基本數(shù)據(jù)類(lèi)型:
| ctypes 類(lèi)型 | C 類(lèi)型 | Python 類(lèi)型 |
|---|---|---|
| [c_bool] | _Bool | bool (1) |
| [c_char] | char | 單字符字節(jié)串對(duì)象 |
| [c_wchar] | wchar_t | 單字符字符串 |
| [c_byte] | char | int |
| [c_ubyte] | unsigned char | int |
| [c_short] | short | int |
| [c_ushort] | unsigned short | int |
| [c_int] | int | int |
| [c_uint] | unsigned int | int |
| [c_long] | long | int |
| [c_ulong] | unsigned long | int |
| [c_longlong] | __int64 或 long long | int |
| [c_ulonglong] | unsigned __int64 或 unsigned long long | int |
| [c_size_t] | size_t | int |
| [c_ssize_t] | ssize_t 或 Py_ssize_t | int |
| [c_float] | float | float |
| [c_double] | double | float |
| [c_longdouble] | long double | float |
| [c_char_p] | char * (NUL terminated) | 字節(jié)串對(duì)象或 None |
| [c_wchar_p] | wchar_t * (NUL terminated) | 字符串或 None |
| [c_void_p] | void * | int 或 None |
環(huán)境
開(kāi)發(fā)工具:Clion
C語(yǔ)言版本:C11
Python版本:Python3.8
創(chuàng)建項(xiàng)目

CMakeLists.txt
# 指定 CMake 的最低版本要求 cmake_minimum_required(VERSION 3.30) # 定義項(xiàng)目名稱(chēng)和支持的語(yǔ)言類(lèi)型 project(CLibSharedDemo C) # 設(shè)置 C 標(biāo)準(zhǔn)版本為 C11 set(CMAKE_C_STANDARD 11) # 添加共享庫(kù)目標(biāo),將 library.c 編譯為動(dòng)態(tài)庫(kù) (Windows 下為 .dll,Linux 下為 .so,macOS 下為 .dylib) add_library(CLibSharedDemo SHARED library.c)
library.h
#ifndef CLIBSHAREDDEMO_LIBRARY_H
#define CLIBSHAREDDEMO_LIBRARY_H
#include <wchar.h>
void plus(int a, int *result);
void *process_void_pointer(void *ptr);
_Bool is_even(int num);
int add_int(int a, int b);
short add_short(short a, short b);
long add_long(long a, long b);
long long add_longlong(long long a, long long b);
unsigned int add_unsigned_int(unsigned int a, unsigned int b);
unsigned short add_unsigned_short(unsigned short a, unsigned short b);
unsigned long add_unsigned_long(unsigned long a, unsigned long b);
unsigned long long add_unsigned_longlong(unsigned long long a, unsigned long long b);
float add_float(float a, float b);
double add_double(double a, double b);
char to_upper(char c);
wchar_t to_upper_wchar(wchar_t wc);
char *copy_string(const char *src, char *dest);
wchar_t *copy_wstring(const wchar_t *src, wchar_t *dest);
size_t add_size_t(size_t a, size_t b);
ssize_t add_ssize_t(ssize_t a, ssize_t b);
void fill_array(int *arr, int size);
typedef struct {
char name[50];
int age;
} Person;
Person update_person_by_value(Person p);
void update_person_by_pointer(Person *p);
#endif //CLIBSHAREDDEMO_LIBRARY_H
library.c
#include "library.h"
#include <stdio.h>
#include <string.h>
#include <wchar.h>
// void
void plus(const int a, int *result) {
*result = a + 1;
}
// void *
void *process_void_pointer(void *ptr) {
return ptr;
}
// _Bool
_Bool is_even(const int num) {
return num % 2 == 0;
}
// int
int add_int(const int a, const int b) {
return a + b;
}
// short
short add_short(const short a, const short b) {
return a + b;
}
// long
long add_long(const long a, const long b) {
return a + b;
}
// long long
long long add_longlong(const long long a, const long long b) {
return a + b;
}
// unsigned int
unsigned int add_unsigned_int(const unsigned int a, const unsigned int b) {
return a + b;
}
// unsigned short
unsigned short add_unsigned_short(const unsigned short a, const unsigned short b) {
return a + b;
}
// unsigned long
unsigned long add_unsigned_long(const unsigned long a, const unsigned long b) {
return a + b;
}
// unsigned long long
unsigned long long add_unsigned_longlong(const unsigned long long a, const unsigned long long b) {
return a + b;
}
// float
float add_float(const float a, const float b) {
return a + b;
}
// double
double add_double(const double a, const double b) {
return a + b;
}
// char
char to_upper(const char c) {
if (c >= 'a' && c <= 'z') {
return c - ('a' - 'A');
}
return c;
}
// wchar_t
wchar_t to_upper_wchar(const wchar_t wc) {
if (wc >= L'a' && wc <= L'z') {
return wc - (L'a' - L'A');
}
return wc;
}
// char *
char *copy_string(const char *src, char *dest) {
strcpy(dest, src);
return dest;
}
// wchar_t *
wchar_t *copy_wstring(const wchar_t *src, wchar_t *dest) {
wcscpy(dest, src);
return dest;
}
// size_t
size_t add_size_t(const size_t a, const size_t b) {
return a + b;
}
// ssize_t
ssize_t add_ssize_t(const ssize_t a, const ssize_t b) {
return a + b;
}
// arr
void fill_array(int *arr, int size) {
for (int i = 0; i < size; i++) {
arr[i] = arr[i] * i;
}
}
// struct
Person update_person_by_value(Person p) {
p.age += 1; // 修改 age
return p;
}
void update_person_by_pointer(Person *p) {
if (p != NULL) {
p->age += 1; // 修改 age
}
}
編譯
選擇菜單【Build】 - 【Build Project】,編譯生成動(dòng)態(tài)庫(kù)在 cmake-build-debug 目錄下。
使用
# main.py
import ctypes
import platform
"""
官方參考文檔:https://docs.python.org/zh-cn/3.8/library/ctypes.html
"""
# 獲取當(dāng)前操作系統(tǒng)的名稱(chēng)
current_platform = platform.system()
# 根據(jù)操作系統(tǒng)設(shè)置庫(kù)的路徑
if current_platform == "Windows":
lib = ctypes.CDLL("./cmake-build-debug/libCLibSharedDemo.dll") # Windows
elif current_platform == "Linux":
lib = ctypes.CDLL("./cmake-build-debug/libCLibSharedDemo.so") # Linux
elif current_platform == "Darwin": # macOS的名稱(chēng)是 Darwin
lib = ctypes.CDLL("./cmake-build-debug/libCLibSharedDemo.dylib") # macOS
else:
raise OSError("Unsupported platform")
""" 空值 """
# void
lib.plus.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.c_int))
lib.plus.restype = None
result = ctypes.c_int() # 創(chuàng)建一個(gè) ctypes 整型變量作為結(jié)果
lib.plus(5, ctypes.byref(result)) # 使用 ctypes.byref 傳遞指針
print("void:", result.value) # 輸出: Result: 6
# void *
lib.process_void_pointer.argtypes = (ctypes.c_void_p,)
lib.process_void_pointer.restype = ctypes.c_void_p
ptr = ctypes.pointer(ctypes.c_int(42))
print("void *: ", lib.process_void_pointer(ptr)) # 輸出: 2320620323976
""" 布爾 """
# _Bool -> c_bool
lib.is_even.argtypes = (ctypes.c_int,)
lib.is_even.restype = ctypes.c_bool
print("_Bool:", lib.is_even(4)) # 輸出: True
""" 整數(shù)/浮點(diǎn)數(shù) """
# int -> c_int
lib.add_int.argtypes = (ctypes.c_int, ctypes.c_int)
lib.add_int.restype = ctypes.c_int
print("int:", lib.add_int(10, 20)) # 輸出: 30
# short -> c_short
lib.add_short.argtypes = (ctypes.c_short, ctypes.c_short)
lib.add_short.restype = ctypes.c_short
print("short:", lib.add_short(3200, 10)) # 輸出: 3210
# long -> c_long
lib.add_long.argtypes = (ctypes.c_long, ctypes.c_long)
lib.add_long.restype = ctypes.c_long
print("long:", lib.add_long(10000, 2000)) # 輸出: 12000
# long long -> c_longlong
lib.add_longlong.argtypes = (ctypes.c_longlong, ctypes.c_longlong)
lib.add_longlong.restype = ctypes.c_longlong
print("long long:", lib.add_longlong(100000000000, 200000000000)) # 輸出: 300000000000
# unsigned int -> c_uint
lib.add_unsigned_int.argtypes = (ctypes.c_uint, ctypes.c_uint)
lib.add_unsigned_int.restype = ctypes.c_uint
print("unsigned int:", lib.add_unsigned_int(10, 20)) # 輸出: 30
# unsigned short -> c_ushort
lib.add_unsigned_short.argtypes = (ctypes.c_ushort, ctypes.c_ushort)
lib.add_unsigned_short.restype = ctypes.c_ushort
print("unsigned short:", lib.add_unsigned_short(3200, 10)) # 輸出: 3210
# unsigned long -> c_ulong
lib.add_unsigned_long.argtypes = (ctypes.c_ulong, ctypes.c_ulong)
lib.add_unsigned_long.restype = ctypes.c_ulong
print("unsigned long:", lib.add_unsigned_long(10000, 2000)) # 輸出: 12000
# unsigned long long -> c_ulonglong
lib.add_unsigned_longlong.argtypes = (ctypes.c_ulonglong, ctypes.c_ulonglong)
lib.add_unsigned_longlong.restype = ctypes.c_ulonglong
print("unsigned long long:", lib.add_unsigned_longlong(100000000000, 200000000000)) # 輸出: 300000000000
# float -> c_float
lib.add_float.argtypes = (ctypes.c_float, ctypes.c_float)
lib.add_float.restype = ctypes.c_float
print("float:", lib.add_float(3.5, 2.0)) # 輸出: 5.5
# double -> c_double
lib.add_double.argtypes = (ctypes.c_double, ctypes.c_double)
lib.add_double.restype = ctypes.c_double
print("double:", lib.add_double(1.5, 2.5)) # 輸出: 4.0
""" 字符/字符串 """
# char -> c_char
lib.to_upper.argtypes = (ctypes.c_char,)
lib.to_upper.restype = ctypes.c_char
print("char:", lib.to_upper("a".encode()).decode()) # 輸出: 'A'
# wchar_t -> c_wchar
lib.to_upper_wchar.argtypes = (ctypes.c_wchar,)
lib.to_upper_wchar.restype = ctypes.c_wchar
print("wchar_t:", lib.to_upper_wchar("a")) # 輸出: 'A'
# char * -> c_char_p
lib.copy_string.argtypes = (ctypes.c_char_p, ctypes.c_char_p)
lib.copy_string.restype = ctypes.c_char_p
src_str = "Hello"
dest_str = ctypes.create_string_buffer(100) # 預(yù)留 100 字節(jié)緩沖區(qū)
result = lib.copy_string(src_str.encode(), dest_str)
print("char *:", result.decode()) # 輸出: 'Hello'
# wchar_t * -> c_wchar_p
lib.copy_wstring.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p)
lib.copy_wstring.restype = ctypes.c_wchar_p
src_wstr = "Hello Wide"
dest_wstr = ctypes.create_unicode_buffer(100) # 預(yù)留 100 個(gè)寬字符緩沖區(qū)
result = lib.copy_wstring(src_wstr, dest_wstr)
print("wchar_t *:", result) # 輸出: 'Hello Wide'
""" 指針 """
# int * -> ctypes.POINTER(ctypes.c_int)
lib.plus.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.c_int))
lib.plus.restype = None
result = ctypes.c_int()
lib.plus(5, ctypes.byref(result)) # ctypes.byref 直接傳遞原有變量的地址
print("int *:", result.value) # 輸出: Result: 6
result = ctypes.c_int()
lib.plus(5, ctypes.pointer(result)) # ctypes.pointer 顯式地創(chuàng)建一個(gè)指針對(duì)象
print("int *:", result.value) # 輸出: Result: 6
""" 內(nèi)存大小 """
# size_t -> c_size_t
lib.add_size_t.argtypes = (ctypes.c_size_t, ctypes.c_size_t)
lib.add_size_t.restype = ctypes.c_size_t
print("size_t:", lib.add_size_t(10, 20)) # 輸出: 30
# ssize_t -> c_ssize_t
lib.add_ssize_t.argtypes = (ctypes.c_ssize_t, ctypes.c_ssize_t)
lib.add_ssize_t.restype = ctypes.c_ssize_t
print("ssize_t:", lib.add_ssize_t(10, 20)) # 輸出: 30
""" 數(shù)組 """
lib.fill_array.argtypes = (ctypes.POINTER(ctypes.c_int), ctypes.c_int)
lib.fill_array.restype = None
ls = [1, 3, 5]
arr = (ctypes.c_int * len(ls))(*ls)
lib.fill_array(arr, len(arr))
print("array:", list(arr)) # array: [0, 3, 10]
""" 結(jié)構(gòu)體 """
class Person(ctypes.Structure):
_fields_ = [("name", ctypes.c_char * 50), ("age", ctypes.c_int)]
# 情況 1:入?yún)⒑头祷刂刀际墙Y(jié)構(gòu)體
lib.update_person_by_value.argtypes = (Person,)
lib.update_person_by_value.restype = Person
person1 = Person(name="Alice".encode(), age=25)
print(f"Before (Value): name={person1.name.decode()}, age={person1.age}")
updated_person = lib.update_person_by_value(person1)
print(f"After (Value): name={updated_person.name.decode()}, age={updated_person.age}")
# 情況 2:入?yún)榻Y(jié)構(gòu)體指針
lib.update_person_by_pointer.argtypes = (ctypes.POINTER(Person),)
lib.update_person_by_pointer.restype = None
person2 = Person(name="Bob".encode(), age=30)
print(f"Before (Pointer): name={person2.name.decode()}, age={person2.age}")
lib.update_person_by_pointer(ctypes.byref(person2))
print(f"After (Pointer): name={person2.name.decode()}, age={person2.age}")
到此這篇關(guān)于Python調(diào)用C語(yǔ)言動(dòng)態(tài)庫(kù)的方法小結(jié)的文章就介紹到這了,更多相關(guān)Python調(diào)用C語(yǔ)言動(dòng)態(tài)庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用tqdm顯示Python代碼執(zhí)行進(jìn)度功能
在使用Python執(zhí)行一些比較耗時(shí)的操作時(shí),為了方便觀察進(jìn)度,通常使用進(jìn)度條的方式來(lái)可視化呈現(xiàn)。這篇文章主要介紹了使用tqdm顯示Python代碼執(zhí)行進(jìn)度,需要的朋友可以參考下2019-12-12
解析pip安裝第三方庫(kù)但PyCharm中卻無(wú)法識(shí)別的問(wèn)題及PyCharm安裝第三方庫(kù)的方法教程
這篇文章主要介紹了解析pip安裝第三方庫(kù)但PyCharm中卻無(wú)法識(shí)別的問(wèn)題及PyCharm安裝第三方庫(kù)的方法教程,本文圖文并茂給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
Python?實(shí)現(xiàn)多表和工作簿合并及一表按列拆分
這篇文章主要介紹了Python?實(shí)現(xiàn)多表和工作簿合并及一表按列拆分,文章圍繞主題展開(kāi)詳細(xì)的資料介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-05-05
python使用BeautifulSoup分析網(wǎng)頁(yè)信息的方法
這篇文章主要介紹了python使用BeautifulSoup分析網(wǎng)頁(yè)信息的方法,涉及Python使用BeautifulSoup模塊分析網(wǎng)頁(yè)信息的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04
Python函數(shù)式編程模塊functools的使用與實(shí)踐
本文主要介紹了Python函數(shù)式編程模塊functools的使用與實(shí)踐,教你如何使用?functools.partial、functools.wraps、functools.lru_cache?和?functools.reduce,感興趣的可以了解一下2024-03-03
使用python爬取4K壁紙保存到本地文件夾的全過(guò)程
圖片信息豐富多彩,許多網(wǎng)站上都有大量精美的圖片資源,有時(shí)候我們可能需要批量下載這些圖片,而手動(dòng)一個(gè)個(gè)下載顯然效率太低,所以本文給大家介紹了使用python爬取4K壁紙保存到本地文件夾的全過(guò)程,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2024-03-03
python中l(wèi)strip()截掉字符的實(shí)例講解
在本篇文章里小編給大家整理的是一篇關(guān)于python中l(wèi)strip()截掉字符的實(shí)例講解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2021-05-05
簡(jiǎn)單談?wù)刾ython中的Queue與多進(jìn)程
本文給大家簡(jiǎn)單總結(jié)了下再Python中的隊(duì)列對(duì)象(queue)以及多進(jìn)程(multiprocessing),非常的簡(jiǎn)單實(shí)用,有需要的小伙伴可以參考下2016-08-08

