Передайте указатель на динамически назначенную переменную функции для удаления

#python #pointers #ctypes

Вопрос:

libtestm.dll код

 #pragma once
#define EXPORT extern "C" __declspec(dllexport)
#include <iostream>
#include <vector>

class TestValue
{
public:
    std::vector<int> v;
    TestValue()
    {
        for (size_t i = 0; i < 10; i  )
        {
            v.push_back(i);
        }
    }
    ~TestValue()
    {
        std::cout << "Deteled Test Value" << std::endl;
    }
};

EXPORT TestValue *TestReturn()
{
    return new TestValue();
}

EXPORT size_t TestData(TestValue *pt, int **array)
{
    *array = pt->v.data();
    return pt->v.size();
}

EXPORT void TestDelete(TestValue *pt)
{
    if(pt)
    {
        delete pt;
    }
}
 

TestLib.py

 import os, sys
from ctypes import *
import Libs.Utils as u

__dllname__: str = 'libtestm.dll'

__dllfile__: str = None
__dll__: cdll = None
__dllfile__, __dll__ = u.FindLoadDll(__dllname__, __file__) # get dll from this method

if __name__ == "__main__":
    v = __dll__.TestReturn()
    __dll__.TestDelete(v)
 

вывод на консоль при запуске этого кода

 Deteled Test Value
Traceback (most recent call last):
  File "d:MyProjectsGitRepoCodePythonDllsTestLib.py", line 31, in <module>
    __dll__.TestDelete(v)
OSError: exception: access violation reading 0x00000000A20E2490
 

Было трудно использовать стандартную библиотеку c с типами ctypes python, поэтому я попытался использовать ее, заключив в класс. Освобождение указателя на динамически выделяемую переменную прошло успешно, но произошла ошибка. Пожалуйста, дайте мне знать, в чем я не прав. Спасибо.

Ответ №1:

Это стандартная ошибка большинства начинающих ctypes пользователей. ctypes предполагает типы аргументов, если они не указаны, и это обычно c_int или указатель для аргументов и c_int для возвращаемых типов. Поскольку TestValue* является 64-разрядным, c_int возвращаемое значение является 32-разрядным и усекает его. Решение состоит в том, чтобы привыкнуть всегда указывать .argtypes и .restype для каждой используемой функции:

test.cpp:

 #pragma once
#define EXPORT extern "C" __declspec(dllexport)
#include <iostream>
#include <vector>

class TestValue {
public:
    std::vector<int> v;
    TestValue() {
        for (int i = 0; i < 10; i  )
            v.push_back(i);
    }
    ~TestValue() {
        std::cout << "Deleted Test Value" << std::endl;
    }
};

EXPORT TestValue *TestReturn() {
    return new TestValue();
}

EXPORT size_t TestData(TestValue *pt, int **array) {
    *array = pt->v.data();
    return pt->v.size();
}

EXPORT void TestDelete(TestValue *pt) {
    if(pt)
        delete pt;
}
 

test.py:

 from ctypes import *

dll = CDLL('./test')
dll.TestReturn.argtypes = ()
dll.TestReturn.restype = c_void_p
dll.TestData.argtypes = c_void_p,POINTER(POINTER(c_int))
dll.TestData.restype = c_size_t
dll.TestDelete.argtypes = c_void_p,
dll.TestDelete.restype = None

v = dll.TestReturn()
data = POINTER(c_int)()
size = dll.TestData(v,byref(data))
print(data[:size])
dll.TestDelete(v)
 

Выход:

 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Deleted Test Value
 

Комментарии:

1. Большое спасибо! Несмотря на то, что я пропустил 64-разрядную конфигурацию, еще больше спасибо за полное объяснение. Как вы уже сказали, я новичок как в C , так и в Python. Мне нужно больше учиться. Еще раз спасибо вам за идеальный ответ.