#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. Мне нужно больше учиться. Еще раз спасибо вам за идеальный ответ.