最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python使用ctypes實(shí)現(xiàn)與C++互相調(diào)用的實(shí)踐教程

 更新時(shí)間:2026年02月04日 08:37:29   作者:愛吃芒果的蘑菇  
這篇文章主要為大家詳細(xì)介紹了Python如何使用ctypes實(shí)現(xiàn)與C++互相調(diào)用,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

背景

小H上次使用了pybind11來調(diào)用C++的方法,這次同樣是在項(xiàng)目中遇到了需要在py層調(diào)用C++方法的情況,現(xiàn)在對(duì)于性能的需求更加敏感,所以需要使用C++的底層方法來獲得結(jié)果(當(dāng)然也可能只是因?yàn)镃++有這個(gè)方法,直接拿來用比較方便),選擇ctypes應(yīng)該也是因?yàn)檫@個(gè)比較方便吧。

示例

在C++側(cè),我們需要實(shí)現(xiàn)一個(gè)函數(shù),然后導(dǎo)出一個(gè)動(dòng)態(tài)庫(kù)方法,這里樓主從py層傳入了一個(gè)回調(diào)函數(shù),返回了對(duì)應(yīng)的字符結(jié)果。

在py側(cè),首先需要使用ctypes.CDLL加載剛才編譯出的動(dòng)態(tài)庫(kù),聲明對(duì)應(yīng)的方法,之后實(shí)現(xiàn)一個(gè)回調(diào)函數(shù)進(jìn)行傳入。

C++動(dòng)態(tài)庫(kù)實(shí)現(xiàn)

#include <iostream>
#include <string>

// 回調(diào)類型:void callback(int, const char*)
using CallbackType = void(*)(int, const char*);

extern "C" {

// 導(dǎo)出函數(shù):循環(huán)調(diào)用回調(diào)
void run_with_callback(CallbackType cb, int count) {
    if (!cb) {
        std::cerr << "[C++] callback is null" << std::endl;
        return;
    }

    std::cout << "[C++] run_with_callback start, count = " << count << std::endl;

    for (int i = 0; i < count; ++i) {
        std::cout << "[C++] before calling callback, i = " << i << std::endl;

        std::string message = "msg from C++ index = " + std::to_string(i);
        cb(i, message.c_str());  // 回調(diào)到 Python

        std::cout << "[C++] after calling callback, i = " << i << std::endl;
    }

    std::cout << "[C++] run_with_callback end" << std::endl;
}

} // extern "C"

ps:C++ 默認(rèn)會(huì)對(duì)函數(shù)名做 name mangling(名字改編),導(dǎo)致動(dòng)態(tài)庫(kù)中的符號(hào)名變復(fù)雜;ctypes按 C ABI 去找函數(shù)名,如果不顯式用 extern "C",Python 側(cè)很難直接按名字找到

用CMake編譯成動(dòng)態(tài)庫(kù)

cmake_minimum_required(VERSION 3.10)
project(pyc_callback_demo LANGUAGES CXX)

add_library(mycallback SHARED callback_lib.cpp)

set_target_properties(mycallback PROPERTIES
    OUTPUT_NAME "mycallback"
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED YES
)

構(gòu)建

mkdir -p build
cd build
cmake ..
cmake --build .

這樣就得到了一個(gè).so文件,供py側(cè)加載。

python加載動(dòng)態(tài)庫(kù)并調(diào)用

  • 用 @CALLBACK_CTYPE 裝飾 Python 函數(shù),ctypes 會(huì)把它包裝成 C 函數(shù)指針。
  • 字符串參數(shù)在 Python 中收到的是 bytes,需要手動(dòng)解碼
import ctypes
import pathlib
import os

# 當(dāng)前文件所在目錄
BASE_DIR = pathlib.Path(__file__).resolve().parent

LIB_PATH = BASE_DIR / "cpp_lib" / "build" / "libmycallback.so"

if not LIB_PATH.exists():
    raise FileNotFoundError(f"找不到動(dòng)態(tài)庫(kù): {LIB_PATH}. 請(qǐng)先在 cpp_lib 目錄下用 CMake 編譯生成 libmycallback.so")

# 加載動(dòng)態(tài)庫(kù)
lib = ctypes.CDLL(str(LIB_PATH))

# 定義 C 端回調(diào)類型
# 第二個(gè)參數(shù)用 ctypes.c_char_p(C 端是 const char*)
CALLBACK_CTYPE = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)

# 聲明 C 函數(shù)的簽名:void run_with_callback(CallbackType cb, int count)
lib.run_with_callback.argtypes = [CALLBACK_CTYPE, ctypes.c_int]
lib.run_with_callback.restype = None


# Python 側(cè)的回調(diào)實(shí)現(xiàn)
@CALLBACK_CTYPE
def py_callback(i: int, msg: bytes) -> None:
    # msg 是 bytes,需要按合適編碼解碼,這里假設(shè) UTF-8
    text = msg.decode("utf-8") if msg is not None else "<NULL>"
    print(f"[Python] in callback, i = {i}, msg = {text}")


def main() -> None:
    print("[Python] before calling C function")

    # 調(diào)用 C++ 庫(kù)函數(shù),并把 Python 回調(diào)傳進(jìn)去
    lib.run_with_callback(py_callback, 3)

    print("[Python] after calling C function")


if __name__ == "__main__":
    main()

ctypes與pybind11區(qū)別

ctypes:純 Python 側(cè)綁定

不需要在 C++ 里寫任何“綁定代碼”,只要提供 C ABI 的動(dòng)態(tài)庫(kù)。

Python 側(cè)通過 ctypes.CDLL、CFUNCTYPE 等描述函數(shù)簽名。

只要函數(shù)滿足“C 風(fēng)格接口”(例如 extern "C" + 基本類型/指針),不在意具體是由 C 還是 C++ 實(shí)現(xiàn)。

非常適合:

  • 已經(jīng)有現(xiàn)成 C 庫(kù) / C 接口的 C++ 庫(kù)
  • 簡(jiǎn)單函數(shù)調(diào)用、回調(diào)、不復(fù)雜的數(shù)據(jù)結(jié)構(gòu)

pybind11:在 C++ 側(cè)寫綁定,生成 Python 模塊

是一個(gè)頭文件庫(kù),寫法大致像如之前提供的示例一致

編譯后得到的是一個(gè) Python 擴(kuò)展模塊(.so),import mymodule 就像普通 Python 包一樣使用。

可以非常自然地暴露:

  • C++ 類、方法、構(gòu)造函數(shù)
  • STL 容器(std::vectorstd::map 等)
  • 智能指針、異常、枚舉等

對(duì)復(fù)雜 C++ API 的封裝能力遠(yuǎn)強(qiáng)于 ctypes。

結(jié)語

經(jīng)過這兩次學(xué)習(xí),讓小H更加能夠體會(huì)到在代碼的世界中,語言并不是孤立的,弱化了對(duì)語言的重視程度,學(xué)習(xí)編程更應(yīng)該將編程語言看作一種工具,什么時(shí)候什么情況該換就換,大家各自完成各自擅長(zhǎng)的部分,更有利于找到性能與效率的均衡點(diǎn)。

到此這篇關(guān)于Python使用ctypes實(shí)現(xiàn)與C++互相調(diào)用的實(shí)踐教程的文章就介紹到這了,更多相關(guān)Python與C++互調(diào)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python 使用cx-freeze打包程序的實(shí)現(xiàn)

    python 使用cx-freeze打包程序的實(shí)現(xiàn)

    這篇文章主要介紹了python 使用cx-freeze打包程序的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • 基于Python制作一個(gè)惡搞代碼

    基于Python制作一個(gè)惡搞代碼

    這篇文章主要為大家詳細(xì)介紹了如何基于Python和Tkinter制作一個(gè)惡搞代碼--無限彈窗,每天寫一些有趣的小程序,帶你成為一個(gè)浪漫的程序員
    2023-08-08
  • python編譯pyc文件的過程解析

    python編譯pyc文件的過程解析

    pyc是一種二進(jìn)制文件,是由py文件經(jīng)過編譯后,生成的文件,是一種byte code,這篇文章主要介紹了python編譯pyc文件,需要的朋友可以參考下
    2021-09-09
  • python實(shí)現(xiàn)定時(shí)任務(wù)的八種方式總結(jié)

    python實(shí)現(xiàn)定時(shí)任務(wù)的八種方式總結(jié)

    在日常工作中,我們常常會(huì)用到需要周期性執(zhí)行的任務(wù),下面這篇文章主要給大家介紹了關(guān)于python實(shí)現(xiàn)定時(shí)任務(wù)的八種方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • Python Tkinter實(shí)現(xiàn)將ZIP中的CSV批量轉(zhuǎn)換為Excel

    Python Tkinter實(shí)現(xiàn)將ZIP中的CSV批量轉(zhuǎn)換為Excel

    這篇文章主要為大家詳細(xì)介紹了Python如何結(jié)合Tkinter實(shí)現(xiàn)將ZIP中的CSV批量轉(zhuǎn)換為Excel,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下
    2026-01-01
  • Python?pandas.replace的用法詳解

    Python?pandas.replace的用法詳解

    在處理數(shù)據(jù)的時(shí)候,很多時(shí)候會(huì)遇到批量替換的情況,如果一個(gè)一個(gè)去修改效率過低,也容易出錯(cuò),replace()是很好的方法,下面這篇文章主要給大家介紹了關(guān)于Python?pandas.replace用法的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • Python中利用all()來優(yōu)化減少判斷的實(shí)例分析

    Python中利用all()來優(yōu)化減少判斷的實(shí)例分析

    在本篇文章里小編給大家整理的是一篇關(guān)于Python中利用all()來優(yōu)化減少判斷的實(shí)例分析內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2021-06-06
  • python異步Web框架sanic的實(shí)現(xiàn)

    python異步Web框架sanic的實(shí)現(xiàn)

    這篇文章主要介紹了python異步Web框架sanic的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • Python爬取個(gè)人微信朋友信息操作示例

    Python爬取個(gè)人微信朋友信息操作示例

    這篇文章主要介紹了Python爬取個(gè)人微信朋友信息操作,涉及Python使用itchat包實(shí)現(xiàn)微信朋友信息爬取操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2018-08-08
  • 詳解Python+Turtle繪制奧運(yùn)標(biāo)志的實(shí)現(xiàn)

    詳解Python+Turtle繪制奧運(yùn)標(biāo)志的實(shí)現(xiàn)

    turtle庫(kù)是Python標(biāo)準(zhǔn)庫(kù)之一,是入門級(jí)的圖形繪制函數(shù)庫(kù)。本文就將利用turtle庫(kù)繪制一個(gè)奧運(yùn)標(biāo)志—奧運(yùn)五環(huán),感興趣的可以學(xué)習(xí)一下
    2022-02-02

最新評(píng)論

阿合奇县| 集安市| 大方县| 微山县| 天柱县| 青海省| 东宁县| 准格尔旗| 商城县| 凭祥市| 南召县| 上杭县| 敖汉旗| 旬阳县| 西畴县| 黄山市| 乐都县| 蒙城县| 乌什县| 象州县| 同江市| 黔西| 丽江市| 双峰县| 门源| 柘城县| 赤城县| 万盛区| 峨边| 政和县| 彭山县| 隆尧县| 广丰县| 河源市| 弥渡县| 焉耆| 元氏县| 北安市| 汨罗市| 高要市| 乌什县|