0

I want to run a C++ function from python that returns an int* array by reference and converts it into a python list.

Here is the example C++ code:

#include "stdafx.h"
#include <iostream>

#define DLLEXPORT extern "C" __declspec(dllexport)

DLLEXPORT int getResponse(int*& hash_list)
{

    std::cout << hash_list << std::endl;

    int* hashes = new int[3];
    hashes[0] = 8;
    hashes[1] = 9;
    hashes[2] = 10;
    hash_list = hashes;

    std::cout << hash_list << std::endl;
    std::cout << *hash_list << std::endl;
    std::cout << *(hash_list + 1) << std::endl;
    std::cout << *(hash_list + 2) << std::endl;

    return 0;
}

DLLEXPORT void testDLL()
{
    std::cout << "DLL can be read" << std::endl;
}

Here is my best attempt in python:

from ctypes import cdll, c_int, POINTER, ARRAY, byref

LIB = cdll.LoadLibrary("<path to DLL>")

LIB.testDLL()

func = LIB.getResponse
itype = c_int
func.argtypes = [POINTER(ARRAY(itype,3))]
func.restype = c_int

chashes = (itype * 3)(*[0,1,2])
print(chashes)

func(byref(chashes))

print(chashes)
print(list(chashes))

This is the output:

DLL can be read
<ctypes.c_long_Array_3 object at 0x000001B00FB7FEC8>
0000000100000000
000001B00DB0AC70
8
9
10
<ctypes.c_long_Array_3 object at 0x000001B00FB7FEC8>
[229682288, 432, 2]

This approach seems to have some success, however I think the initial array passed to the C++ function has invalid entries. And then the returned values are mangled anyway.

Is this possible with ctypes? Any suggestions would be appreciated.

I also tried using a c_void_p instead of the ARRAY. In that case it also seems to work, but I don't know how to turn the resulting pointer into a python list.

1
  • 1
    Cffi is a newer library that can do the same job Commented Mar 13, 2019 at 16:01

1 Answer 1

1

ctypes accesses C interfaces. C doesn't have pointer references, but when treated as extern "C" a pointer reference is marshaled the same as a pointer pointer. Just don't pass None from Python since C++ will see that as a null reference. You'd be better off actually declaring the function to take int** so you can deal with the possibility that None could be passed from Python.

Use:

func.argtypes = [POINTER(POINTER(c_int))]

Call it with:

p = POINTER(c_int)()
func(byref(p))
print(p[:3])
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.