Python ctypes: how to free memory? Getting invalid pointer error

后端 未结 2 1512
旧巷少年郎
旧巷少年郎 2020-12-08 01:39

I want to get some string from a C/C++ library with ctypes into python. My code looks like this:

Code in lib:

const char* get(struct something *x) 
{         


        
相关标签:
2条回答
  • 2020-12-08 02:01

    a cheap hack around freeing the memory is to allocate it statically in C and never free it. only works if you know the maximum amount you need, of course, and if you know that you're done with before a second call to your routine.

    static char _externalStringBuffer[MAX_BUFFER_SIZE];
    char *get() {
        // put characters in _externalStringBuffer
        return _externalStringBuffer;
    }
    
    0 讨论(0)
  • 2020-12-08 02:03

    As David Schwartz pointed out, if you set restype to c_char_p, ctypes returns a regular Python string object. A simple way to get around this is to use a void * and cast the result:

    string.c:

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    char *get(void)
    {
        char *buf = "Hello World";
        char *new_buf = strdup(buf);
        printf("allocated address: %p\n", new_buf);
        return new_buf;
    }
    
    void freeme(char *ptr)
    {
        printf("freeing address: %p\n", ptr);
        free(ptr);
    }
    

    Python usage:

    from ctypes import *
    
    lib = cdll.LoadLibrary('./string.so')
    lib.freeme.argtypes = c_void_p,
    lib.freeme.restype = None
    lib.get.argtypes = []
    lib.get.restype = c_void_p
    
    >>> ptr = lib.get()
    allocated address: 0x9facad8
    >>> hex(ptr)
    '0x9facad8'
    >>> cast(ptr, c_char_p).value
    'Hello World'
    >>> lib.freeme(ptr)
    freeing address: 0x9facad8
    

    You can also use a subclass of c_char_p. It turns out that ctypes doesn't call the getfunc for a subclass of a simple type.

    class c_char_p_sub(c_char_p):
        pass
    
    lib.get.restype = c_char_p_sub
    

    The value attribute returns the string. You can leave the parameter for freeme as the more generic c_void_p. That accepts any pointer type or integer address.

    0 讨论(0)
提交回复
热议问题