如何配置和导出应该 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.
我正在尝试创建一个可以调用的函数,例如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.