Python ctypes为堆栈分配更多内存

Python ctypes为堆栈分配更多内存,python,ctypes,Python,Ctypes,我有一个从python调用的c-dll。dll的输出非常大,我怀疑这会导致错误 OSError: exception: stack overflow 我很确定问题在于输出的大小(大约是4x25x720的两倍)。减小输出的大小(我不想这样做)可以消除错误 在C#中,我可以通过为调用线程分配更多内存来解决这个问题,即 thread = new Thread(() => calculate(ptr_in, ptr_out), 20000000); 是否可以对ctypes执行类似操作 这不是

我有一个从python调用的c-dll。dll的输出非常大,我怀疑这会导致错误

OSError: exception: stack overflow
我很确定问题在于输出的大小(大约是4x25x720的两倍)。减小输出的大小(我不想这样做)可以消除错误

在C#中,我可以通过为调用线程分配更多内存来解决这个问题,即

thread = new Thread(() => calculate(ptr_in, ptr_out), 20000000); 
是否可以对
ctypes
执行类似操作

这不是张贴在这里的问题


编辑 考虑到这个问题,我认为问题不在于输出的大小,而在于实际dll本身所需的空间。即
c\u out internal\u out
ctypes\u test.c中定义。不管怎样,问题还是一样


在C中,我定义了一个测试dll
dll\u ctypes\u test

ctypes\u testT.h

#pragma once
#define N_ELEMENTS 1000
#define N_ARRAYS 50

typedef struct
{
    double var_0;
    double var_1;
    double var_2;
    double var_3;
    double var_4;
    double var_5;
    double var_6;
    double var_7;
    double var_8;
    double var_9;
} element;

typedef struct
{
    int n_elements;
    element elements[N_ELEMENTS];
} arr;

typedef struct
{
    int n_arrays;
    arr arrays[N_ARRAYS];
} c_out;
ctypes\u test.c

#include "ctypes_testT.h"

__declspec(dllexport) void _stdcall dll_ctypes_test(double in, c_out *out)
{
    c_out inner_out;

    //Some caluclations on inner_out
    //Wrap values of inner arr to out
}
还有Python代码

import ctypes

N_ELEMENTS = 1000
N_ARRAYS = 50

class element(ctypes.Structure):
    _fields_ = [('var_0', ctypes.c_double),
                ('var_1', ctypes.c_double),
                ('var_2', ctypes.c_double),
                ('var_3', ctypes.c_double),
                ('var_4', ctypes.c_double),
                ('var_5', ctypes.c_double),
                ('var_6', ctypes.c_double),
                ('var_7', ctypes.c_double),
                ('var_8', ctypes.c_double),
                ('var_9', ctypes.c_double)] 

class arr(ctypes.Structure):
    _fields_ = [('n_elements', ctypes.c_int),
                ('elements', element * N_ELEMENTS)] 

class c_out(ctypes.Structure):
    _fields_ = [('n_arrays', ctypes.c_int),
                ('arrays', arr * N_ARRAYS)]     

dll = ctypes.WinDLL(r'C:\repos\ctypes_test\x64\Debug\ctypes_test.dll')

dll.dll_ctypes_test.argtypes = [ctypes.c_double, ctypes.POINTER(c_out)]  
dll.dll_ctypes_test.restype = None

dll.dll_ctypes_test(5, ctypes.byref(c_out()))
调用Python代码会产生

Traceback (most recent call last):

  File "<ipython-input-15-7c8b287888d0>", line 1, in <module>
   dll.dll_ctypes_test(5, c_out())

OSError: exception: access violation writing 0x00000062BA400000
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
dll.dll\u ctypes\u test(5,c\u out())
OS错误:异常:访问冲突写入0x00000062BA400000
如果我将
N_数组
50
更改为,比如说,
10
。错误消失。

列表

我必须说,我无法使用“常规”Python或IPython重现行为(即使没有修复下面的错误)。也许dll\u ctypes\u测试实现的内容远不止这些

当前问题:

  • dll_ctypes_测试需要一个c_out指针,但您正在传递一个普通的c_out实例。您应该使用ctypes.byref(或ctypes.pointer)。不知道为什么CTypes不会因为它而抱怨
  • C和Python结构定义不匹配。一个例子是arr,它在C中包含一个元素数组,在Python中包含一个元素指针数组(ctypes.pointer)。这是未定义的行为,2必须同步
  • 您将导出函数标记为uu stdcall,但正在用CDLL加载.dll。你应该用温德尔。但由于您使用的是64位(基于您的路径),所以这并没有太大区别
  • 下面是一个示例(代码的修改版本)

    dll00.h:

    #pragma一次
    #如果已定义(_WIN32)
    #如果定义了DLL0\u导出
    #定义DLL00_导出_API__declspec(dllexport)
    #否则
    #定义DLL00_导出_API__declspec(dllimport)
    #恩迪夫
    #否则
    #定义DLL00\u导出\u API
    #恩迪夫
    #定义元素\u计数1000
    #定义数组\u计数50
    类型定义结构{
    双变量0,变量1,变量2,变量3,变量4,
    var5,var6,var7,var8,var9;
    }元素;
    类型定义结构{
    整数大小;
    元素数据[元素计数];
    }阵列1d;
    类型定义结构{
    整数大小;
    数组1d数据[数组计数];
    }阵列2d;
    #如果已定义(uuu cplusplus)
    外部“C”{
    #恩迪夫
    DLL00\u导出\u API无效\u标准调用dll00Func00(双入式,阵列式*pOut);
    #如果已定义(uuu cplusplus)
    }
    #恩迪夫
    
    dll00.c:

    #定义DLL0#u导出
    #包括“dll0.h”
    #包括
    无效dll00Func00(双进,阵列2d*pOut){
    如果(pOut==NULL){
    printf(“从C传递的空数组\n”);
    返回;
    };
    Array2D;
    printf(“从C-外部数组大小:%d\n”,pOut->size);
    }
    
    代码00.py:

    #/usr/bin/env python
    导入系统
    将ctypes导入为ct
    元素计数=1000
    数组计数=50
    类元素(ct结构):
    _字段=列表((((“var{0:d}).format(i),ct.c_double)表示范围(10)中的i)
    类阵列1d(ct结构):
    _字段=[
    (“尺寸”,ct.c_int),
    (“数据”,元素*元素计数),
    ]
    类阵列2D(ct结构):
    _字段=[
    (“尺寸”,ct.c_int),
    (“数据”,数组1d*数组计数),
    ]
    DLL0_NAME=“./dll00.dll”
    def主(*argv):
    dll0=ct.windl(dll0\u名称)
    dll00Func00=dll0.dll00Func00
    dll00Func00.argtypes=[ct.c_double,ct.POINTER(Array2D)]
    #dll00Func00.argtypes=[ct.c_double,Array2D]!!!!定义带指针的第二个参数会触发错误!!!
    mat=Array2D()
    材料尺寸=7
    打印(“数组大小:{0:d}(0x{1:08X})”.format(ct.sizeof(mat),ct.sizeof(mat)))
    dll00Func00(5,ct.byref(材料))
    #dll00Func00(5,mat)
    如果名称=“\uuuuu main\uuuuuuuu”:
    打印(“Python{0:s}{1:d}位在{2:s}\n.format(“.join(sys.version.split(“\n”)中的项的item.strip()),如果sys.maxsize>0x100000000,则为64,否则为32,sys.platform))
    main(*sys.argv[1:])
    打印(“\n完成”)
    
    输出

    e:\Work\Dev\StackOverflow\q060297181>sopr.bat
    ***设置较短的提示,以便粘贴到StackOverflow(或其他)页面时更适合***
    [提示]>“c:\Install\pc032\Microsoft\VisualStudioCommunity\2017\VC\Auxiliary\Build\vcvarsall.bat”x64
    **********************************************************************
    **Visual Studio 2017开发者命令提示符v15.9.20
    **版权所有(c)2017微软公司
    **********************************************************************
    [vcvarsall.bat]环境已初始化为:“x64”
    [提示]>dir/b
    代码00.py
    dll0.h
    dll00.c
    [提示]>cl/nologo/MD/DDLL dll00.c/link/nologo/DLL/OUT:dll00.DLL
    dll00.c
    创建库dll00.lib和对象dll00.exp
    [提示]>dir/b
    代码00.py
    dll0.h
    dll00.c
    dll00.dll
    dll00.exp
    dll00.lib
    dll00.obj
    [提示]>
    [提示]>“e:\Work\Dev\VEnvs\py\u pc064\u 03.07.06\u test0\Scripts\python.exe”code00.py
    win32上的Python 3.7.6(tags/v3.7.6:43364a7ae0,2019年12月19日,00:42:30)[MSC v.1916 64位(AMD64)]64位
    阵列大小:4000408(0x003D0A98)
    从C开始-外部阵列大小:7
    完成。
    
    调用函数或方法时(有一些异常,但这些异常与此无关),堆栈(一个特殊的内存区域)用于存储。正在存储的常见内容:

    • 参数(和返回值),表示调用方和被调用方之间交换的数据
    • 局部变量(在被调用方中),既不是静态的,也不是显式地分配给he