如何配置和导出应该 return 字符数组的函数?

How to configure and export function that should return char array?

我正在尝试创建一个可以调用的函数,例如Python 通过 .dll.

我正在处理字节数组。 这是我要封装的原始函数:

QByteArray getKeys(const QByteArray data, const QByteArray info);

C 风格的接口和实现应该是什么样的?我必须传递 char* 数组和数组大小吗?

我的想法是这样的:

__declspec(dllexport) int getKeys(const char* data, int dataSize, const char* info, int infoSize, const char** result);

该函数会将 return 结果作为副作用,return 值是结果的大小。

清单[Python.Docs]: ctypes - A foreign function library for Python.

@Jarod42 的建议不是使用 std::pair,而是通过 C(兼容)结构
这是一个例子(我的虚拟 getKeys 实现只是 return 连接 2 个 QByteArray 参数:

dll00.cpp:

#include <QtCore/QByteArray>

#include <cstdio>
#include <cstring>


#if defined(_WIN32)
#  define DLL00_EXPORT_API __declspec(dllexport)
#else
#  define DLL00_EXPORT_API
#endif


typedef struct {
    size_t size = 0;
    char *data = nullptr;
} CBuffer;

#if defined(__cplusplus)
extern "C" {
#endif

DLL00_EXPORT_API CBuffer getKeysWrapper(const CBuffer data, const CBuffer info);
DLL00_EXPORT_API void freeBuffer(CBuffer *pBuf);

#if defined(__cplusplus)
}
#endif


static QByteArray getKeys(const QByteArray &data, const QByteArray &info)
{
    printf("C++ - data[%d]: %s\n", data.size(), data.constData());
    printf("C++ - info[%d]: %s\n", info.size(), info.constData());
    QByteArray ret(data);
    ret += info;
    printf("C++ - ret[%d]: %s\n", ret.size(), ret.constData());
    return ret;
}

CBuffer getKeysWrapper(const CBuffer data, const CBuffer info)
{
    QByteArray keys = getKeys(QByteArray(data.data, data.size), QByteArray(info.data, info.size));
    CBuffer buf = { static_cast<size_t>(keys.size()), new char[keys.size()] };
    memcpy(buf.data, keys.constData(), buf.size);
    return buf;
}

void freeBuffer(CBuffer *pBuf)
{
    if (!pBuf)
        return;
    delete[] pBuf->data;
    pBuf->data = nullptr;
    pBuf->size = 0;
}

code00.py:

#!/usr/bin/env python

import sys
import ctypes as ct


DLL_NAME = "./dll00.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")


CharPtr = ct.POINTER(ct.c_char)


class CBuffer(ct.Structure):
    _fields_ = [
        ("size", ct.c_size_t),
        ("data", CharPtr),
    ]


def main(*argv):
    dll00 = ct.CDLL(DLL_NAME)
    getKeysWrapper = dll00.getKeysWrapper
    getKeysWrapper.argtypes = (CBuffer, CBuffer)
    getKeysWrapper.restype = CBuffer
    freeBuffer = dll00.freeBuffer
    freeBuffer.argtypes = (ct.POINTER(CBuffer),)
    freeBuffer.restype = None

    data_b = b"123456"
    data_b_len = len(data_b)
    info_b = b"abcd[=11=]ef"
    info_b_len = len(info_b)

    data = CBuffer(data_b_len, (ct.c_char * data_b_len)(*data_b))
    info = CBuffer(info_b_len, (ct.c_char * info_b_len)(*info_b))

    keys = getKeysWrapper(data, info)
    print("PY - keys:", keys.size, bool(keys.data), " ".join(str(keys.data[i]) for i in range(keys.size)))
    freeBuffer(ct.byref(keys))
    print("PY - keys(freed):", keys.size, bool(keys.data))


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

输出:

[cfati@cfati-5510-0:/mnt/e/Work/Dev/Whosebug/q069346803]> ~/sopr.sh
### Set shorter prompt to better fit when pasted in Whosebug (or other) pages ###

[064bit prompt]> ls
code00.py  dll00.cpp
[064bit prompt]> g++ -fPIC -DQT_NO_VERSION_TAGGING -I/home/cfati/Install/Qt/Qt/5.12.11/gcc_64/include -shared -o dll00.so -L/home/cfati/Install/Qt/Qt/5.12.11/gcc_64/lib dll00.cpp -lQt5Core
[064bit prompt]> ls
code00.py  dll00.cpp  dll00.so
[064bit prompt]> 
[064bit prompt]> LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/home/cfati/Install/Qt/Qt/5.12.11/gcc_64/lib python code00.py 
Python 3.8.10 (default, Jun  2 2021, 10:49:15) [GCC 9.4.0] 064bit on linux

C++ - data[6]: 123456
C++ - info[7]: abcd
C++ - ret[13]: 123456abcd
PY - keys: 13 True b'1' b'2' b'3' b'4' b'5' b'6' b'a' b'b' b'c' b'd' b'\x00' b'e' b'f'
PY - keys(freed): 0 False

Done.