ctypes:如何处理包含结构的结构,其中包含结构......?

ctypes: How to hande structure which contains structure which contains structure which...?

我在 C:

中有一个简单的 API
void init( t_main_struct* p_main_struct );
void calc( t_main_struct* p_main_struct, float* p_result );

我用作:

t_main_struct my_main_struct;
float my_result[3];

init(&my_main_struct);
calc(&my_main_struct, my_result);

我想使用 Python ctypes.

包装上面的 API

问题是,t_main_struct 非常复杂:包含其他结构,包含其他结构,包含其他结构,等等。

在 Python 方面,我真的不需要访问任何 my_main_struct 内部结构,它是一个黑盒子。我只需要知道 my_result 中存储的 calc() 结果。

是否有可能以某种方式简化 main_structctypes 实施?我是否必须指定所有结构成员,包括子结构?或者我可以在不指定所有结构细节的情况下以某种方式传递足够的内存?

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

如果您不关心结构的定义,并且由于两个函数都将指针作为参数,(在 Python 中)您唯一需要做的, 有一个足够大的缓冲区来容纳它(你可以使用 void 指针来引用 struct 实例)。
请记住,如果结构(递归地)包含指向其他结构的指针,则也需要分配这些指针 如果被引用(但我想这必须发生在初始化).

dll00.c:

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


typedef struct _ComplexStruct {
    float f0;
    int i0;
    // The other members
} ComplexStruct;


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

DLL00_EXPORT_API void init(ComplexStruct *pStruct);
DLL00_EXPORT_API void calc(ComplexStruct *pStruct, float *pResult);

#if defined(__cplusplus)
}
#endif


DLL00_EXPORT_API void init(ComplexStruct *pStruct) {
    if (pStruct) {
        pStruct->f0 = -3.5;
        pStruct->i0 = 5;
    }
}


DLL00_EXPORT_API void calc(ComplexStruct *pStruct, float *pResult) {
    if ((pStruct) && (pResult)) {
        (*pResult) = pStruct->f0 * pStruct->i0;
    }
}

code00.py:

#!/usr/bin/env python3

import sys
import ctypes


DLL_NAME = "./dll00.dll"


def main():
    dll00 = ctypes.CDLL(DLL_NAME)

    init = dll00.init
    init.argtypes = [ctypes.c_void_p]
    init.restype = None

    calc = dll00.calc
    calc.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float)]
    calc.restype = None

    buf = ctypes.create_string_buffer(512)  # Create a buffer large enough to hold the structure

    init(buf)
    res = ctypes.c_float()
    calc(buf, ctypes.byref(res))

    print("Result: {0:.3f}".format(res.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\Whosebug\q058233135]> sopr.bat
*** Set shorter prompt to better fit when pasted in Whosebug (or other) pages ***

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

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

[prompt]> cl /nologo /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

Result: -17.500

Done.