Ctypes:“调试断言失败”(字符串!=NULL)将指针传递给使用sprin的dll函数时

2024-09-28 20:52:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用Ctypes为预先编写的DLL文件编写Python包装器,但一直在努力解决指针问题。你知道吗

具体地说,我编译的C++函数的一个简化例子是:

double compute_result(double var1, double var2, char *output_message1, char *output_message2){
    // Computational steps are all here, e.g.
    double result = var1 + var2;

    // then an information message is passed to the output_message1 & 2 location
    sprintf(output_message1, "useful output message 1");
    sprintf(output_message2, "useful output message 2");

    return(result);
}

为了使用ctypes包装它,我尝试如下定义适当的restype和argtype。C++代码没有指定输出消息指针的大小,所以我假设我不必使用cType。你知道吗

dll = ctypes.WinDLL("MyDLL.dll")
f = dll.compute_result
f.restype = c_double
f.argtypes = [c_double, c_double, POINTER(c_char), POINTER(c_char)]

然后,我尝试使用以下方法调用Python中的代码:

# Imports
import ctypes
from ctypes import c_double, c_char, POINTER, addressof, cast

# Input variables
var1 = 1.1
var2 = 2.2

# Create string buffers to hold output message, then convert address to a pointer to pass to dll function
size = 1024  # we know output messages will be shorter than 1024 characters
buf1 = ctypes.create_string_buffer(size)
buf2 = ctypes.create_string_buffer(size)

f(var1, var2, cast(addressof(buf1), POINTER(c_char)), cast(addressof(buf2), POINTER(c_char)))

很遗憾,执行时会显示一个对话框错误,说明:

"Debug Assertion Failed!"

Program: ...somepath_on_my_computer\python.exe
File: ...somepath_on_my_computer\sprintf.c
Line: 110

Expression: (string != NULL)

我知道这意味着我的指针也有一些错误,sprintf也要写输出消息,但我看不出到底是什么错误。 有办法解决这个问题吗?还是我处理指针的方式不对?谢谢!你知道吗


Tags: tomessageoutputstringresultctypesdlldouble
1条回答
网友
1楼 · 发布于 2024-09-28 20:52:27

清单[Python 3.Docs]: ctypes - A foreign function library for Python。你知道吗

buf1buf2(在底层C中)被视为数组,因此它们已经是地址了。你知道吗

去掉addressof,因为它将触发未定义的行为(检查[SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer))。你知道吗

尝试:

f(var1, var2, cast(buf1, POINTER(c_char)), cast(buf2, POINTER(c_char)))

有关更高级的示例,请选中[SO]: How can i cast a double pointer ctype to numpy array? (@CristiFati's answer)。你知道吗

编辑

添加代码示例。你知道吗

dll00.c

#include <stdio.h>

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


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

DLL00_EXPORT_API double dll00Func00(double var1, double var2, char *pMsg1, char *pMsg2);

#if defined(__cplusplus)
}
#endif


double dll00Func00(double var1, double var2, char *pMsg1, char *pMsg2) {
    double result = var1 + var2;
    sprintf(pMsg1, "useful output message 1");
    sprintf(pMsg2, "useful output message 2");
    return result;
}

代码00.py:

#!/usr/bin/env python3

import sys
import ctypes as ct


DLL_NAME = "./dll00.dll"


def main():
    dll00 = ct.CDLL(DLL_NAME)
    dll00Func00 = dll00.dll00Func00
    dll00Func00.argtypes = [ct.c_double, ct.c_double, ct.POINTER(ct.c_char), ct.POINTER(ct.c_char)]
    dll00Func00.restype = ct.c_double

    v1 = 1.1
    v2 = 2.2
    size = 1024
    buf1 = ct.create_string_buffer(size)
    buf2 = ct.create_string_buffer(size)

    res = dll00Func00(v1, v2, ct.cast(buf1, ct.POINTER(ct.c_char)), ct.cast(buf2, ct.POINTER(ct.c_char)))
    print("{0:s} returned: {1:.3f}".format(dll00Func00.__name__, res))
    print(buf1.value, buf2.value)


if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main()
    print("\nDone.")

输出

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q058932240]> sopr.bat
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

[prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2017\VC\Auxiliary\Build\vcvarsall.bat" x64
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.9.17
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

[prompt]> dir /b
code00.py
dll00.c

[prompt]> cl /nologo /MD /DDLL dll00.c  /link /NOLOGO /DLL /OUT:dll00.dll
dll00.c
   Creating library dll00.lib and object dll00.exp

[prompt]> dir /b
code00.py
dll00.c
dll00.dll
dll00.exp
dll00.lib
dll00.obj

[prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code00.py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32

dll00Func00 returned: 3.300
b'useful output message 1' b'useful output message 2'

Done.

值得注意的是,在构建.dll进行调试时,它也可以工作。你知道吗

相关问题 更多 >