簡體   English   中英

CPPYY/CTYPES 將字符串數組作為 char* args[] 傳遞

[英]CPPYY/CTYPES passing array of strings as char* args[]

我最近才開始使用cppyyctypes ,所以這可能是一個有點愚蠢的問題。 我有以下 C++ function:

float method(const char* args[]) {
    ...
}

從 Python 我想將args作為字符串列表傳遞,即:

args = *magic*
x = cppyy.gbl.method(args)

我以前發現過這個,所以我用

def setParameters(strParamList):
    numParams    = len(strParamList)
    strArrayType = ct.c_char_p * numParams
    strArray     = strArrayType()
    for i, param in enumerate(strParamList):
        strArray[i] = param
    lib.SetParams(numParams, strArray)

並來自 Python:

args = setParameters([b'hello', b'world'])

c_types.c_char_p需要一個字節數組。 但是,當調用x = cppyy.gbl.method(args)我得到

TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)

我不完全確定為什么這是錯誤的,因為args<__main__.c_char_p_Array_2> object,我認為應該將其轉換為const char* args[]

為了有一個具體的例子,我將使用它作為.cpp文件:

#include <cstdlib>

extern "C"
float method(const char* args[]) {
    float sum = 0.0f;
    const char **p = args;
    while(*p) {
        sum += std::atof(*p++);
    }
    return sum;
}

我假設它是用g++ method.cpp -fPIC -shared -o method.so編譯的。 鑒於這些假設,下面是一個示例,說明如何從 Python 使用它:

#!/usr/bin/env python3

from ctypes import *

lib = CDLL("./method.so")
lib.method.restype = c_float
lib.method.argtypes = (POINTER(c_char_p),)

def method(args):
    return lib.method((c_char_p * (len(args) + 1))(*args))

print(method([b'1.23', b'45.6']))

我們制作了一個 C 數組來保存 Python arguments。 len(args) + 1確保 null 指針哨兵有空間。

ctypes 沒有公共的 API 可從 C/C++ 用於擴展編寫器,因此 cppyy 對 ctypes 的處理必然有些笨拙。 出了什么問題,生成的const char*的 ctypes 數組的類型是const char*[2]而不是const char*[] ,並且由於 cppyy 對 ctypes 類型進行直接類型匹配,因此失敗了。

照原樣,某處的某些代碼需要將 Python 字符串轉換為低級 C 字符串,並在通話期間堅持使用 memory。 就我個人而言,我會使用一點 C++ 包裝器,而不必在 Python 方面考慮問題。 關鍵是std::vector<std::string>可以處理必要的轉換(例如,因此不需要bytes類型,但如果您願意,當然允許)並且它可以保存臨時 memory。

因此,如果您獲得了這樣的第 3 方接口(僅為了示例而將其內聯用於 cppyy):

import cppyy

cppyy.cppdef("""
    float method(const char* args[], int len) {
        for (int i = 0; i < len; ++i)
            std::cerr << args[i] << " ";
        std::cerr << std::endl;
        return 42.f;
    }
""")

然后我會生成一個包裝器:

# write a C++ wrapper to hide C code
cppyy.cppdef("""
    namespace MyCppAPI {
       float method(const std::vector<std::string>& args) {
           std::vector<const char*> v;
           v.reserve(args.size());
           for (auto& s : args) v.push_back(s.c_str());
           return ::method(v.data(), v.size());
       }
    }
""")

然后用C++版本替換原來的C API:

# replace C version with C++ one for all Python users
cppyy.gbl.method = cppyy.gbl.MyCppAPI.method

對於下游的任何其他人來說,事情將與預期的一樣:

# now use it as expected
cppyy.gbl.method(["aap", "noot", "mies"])

綜上所述,顯然 cppyy 沒有理由不能自動進行這一點包裝。 我創建了這個問題: https://bitbucket.org/wlav/cppyy/issues/235/automatically-convert-python-tuple-of

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM