【问题标题】:How to return a string with null characters from C++ DLL to Python?如何将带有空字符的字符串从 C++ DLL 返回到 Python?
【发布时间】:2021-08-04 21:17:29
【问题描述】:

我正在开发一个调用 C++ 开发的 DLL 的 Python 3 应用程序。 DLL 读取数据库记录并将记录缓冲区返回给 Python 应用程序。我遇到的问题是数据库记录可能包含 x'00'(空)字符。发生这种情况时,返回给 Python 应用程序的记录缓冲区在空字符处被截断。

我正在使用 memcpy 将记录缓冲区复制到 Python 返回区域。我认为 memcpy 复制了指定的字节数,而不管内容如何。

我不是 C++ 程序员,所以我很可能误解了 memcpy 的工作原理。

以下代码 sn-ps 是测试代码示例,将演示我遇到的问题。

这是 DLL:

#include "pch.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>     
#include <iostream>

using namespace std;

#define LIBDLL extern "C" __declspec(dllexport)

LIBDLL int readData_VPRI2(char* buffer, unsigned long buffer_length )

{
    char unsigned buf[20];
    int unsigned buf_len;
    FILE* stream;
    errno_t err;
    err = fopen_s(&stream, "D:\\testfile", "rb");
    if (err != 0) return err;
    fread(buf, buffer_length, 1, stream);
    memcpy(buffer, buf, buffer_length);
    return 0;

}

这是 Python 调用例程:

import ctypes
from ctypes import *

dll = ctypes.CDLL('C:\\Users\\rhkea\\source\\repos\\TestDLL\\x64\\Debug\\TestDLL.dll')

f = open("D:\\testfile", "wb")
test_string = bytes('ABCD\x00efg', encoding='utf-8')
f.write(test_string)
f.close()

char_arr = ctypes.c_char * 500                                      # set up the return area
buffer = char_arr()                                                 # assign the buffer
readData_VPRI2 = dll.readData_VPRI2                                 # get the DLL
readData_VPRI2.restype = ctypes.c_int                               # set the return type
readData_VPRI2.argtypes = (POINTER(c_char), c_long)                 # define the arguments

rc = readData_VPRI2(buffer, len(test_string))                       # call the DLL

print ("rc =", rc)
if rc==0:
    print ("buffer =", buffer.value)
    print ("buffer length = ", len(buffer.value))

Python 执行的输出是:

rc = 0
buffer = b'ABCD'
buffer length =  4

如图所示,返回的缓冲区在 x'00' 处被截断。

我猜我可能会忽略或不理解一些简单的事情。任何有关如何纠正此问题的指导将不胜感激。

提前致谢。

【问题讨论】:

  • sizeof(buffer) 不是缓冲区大小,而是指针的大小。结果真的是在\x00 处截断吗?如果test_string'AB\x00CDefg' 怎么办?
  • 谢谢@MikeCAT。我对 sizeof 不好...我更改了上面的代码示例。将流更改为 test_string = bytes('AB\x00CDefg', encoding='utf-8') 会导致:rc = 0 buffer = b'AB' buffer length = 2

标签: python c++ dll memcpy


【解决方案1】:

事实证明,C++ 代码按设计运行。我关于memcpy 的问题不是问题所在。它按记录工作。

我发现 Python 实际上可能会截断字符串。 cytpes.c_char.value 返回截断的字符串,如我原来的问题中所述。

但如果您使用cyptes.c_char.raw,则返回整个字符串(在我的示例中为buffer)(例如,500 字节),并用 x'00' 填充。所以print(buffer.raw) 返回:

b'AB\x00CDefg\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00... ...\x00'

由于我已经知道我期望返回的记录的长度,我可以简单地从buffer.raw 中分割它。

感谢您的回复。

【讨论】:

    猜你喜欢
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-12
    • 1970-01-01
    • 2018-03-08
    • 2019-08-04
    相关资源
    最近更新 更多