ctypes возвращает строку из c функции

Я – ветеран Python, но не набрал много на C. После полудня, когда я не нашел ничего в Интернете, который работает для меня, я подумал, что попрошу здесь и получить помощь, в которой я нуждаюсь.

Я хочу написать простую функцию C, которая принимает строку и возвращает другую строку. Я планирую связать эту функцию на нескольких языках (Java, Obj-C, Python и т. Д.), Поэтому я думаю, что она должна быть чистой C?

Вот что я до сих пор. Заметьте, что я получаю segfault при попытке получить значение в Python.

Привет

#include <stdlib.h> #include <stdio.h> #include <string.h> const char* hello(char* name) { static char greeting[100] = "Hello, "; strcat(greeting, name); strcat(greeting, "!\n"); printf("%s\n", greeting); return greeting; } 

main.py

 import ctypes hello = ctypes.cdll.LoadLibrary('./hello.so') name = "Frank" c_name = ctypes.c_char_p(name) foo = hello.hello(c_name) print c_name.value # this comes back fine print ctypes.c_char_p(foo).value # segfault 

Я прочитал, что segfault вызвано тем, что C освобождает память, которая была первоначально выделена для возвращаемой строки. Может быть, я просто лаю неправильное дерево?

Каков правильный способ добиться того, чего я хочу?

  • Проверка, являются ли две строки перестановками друг друга в Python
  • открытие другой программы через службу Windows с помощью python
  • Как вы запускаете свой собственный код вместе с циклом событий Tkinter?
  • Панды перетасовывают ряды на определенном уровне
  • Значение tkinter get () python из поля ввода
  • передача kwargs с multiprocessing.pool.map
  • Эффективный способ применения нескольких фильтров к pandas DataFrame или Series
  • Как вставить флажок в форме django
  • 3 Solutions collect form web for “ctypes возвращает строку из c функции”

    n hello.c вы возвращаете локальный массив. Вы должны вернуть указатель на массив, который должен быть динамически объявлен с помощью malloc.

     char* hello(char* name) { char hello[] = "Hello "; char excla[] = "!\n"; char *greeting = malloc ( sizeof(char) * ( strlen(name) + strlen(hello) + strlen(excla) + 1 ) ); if( greeting == NULL) exit(1); strcpy( greeting , hello); strcat(greeting, name); strcat(greeting, excla); return greeting; } 

    Ваша проблема заключается в том, что приветствие было выделено в стеке, но стек уничтожается при возврате функции. Вы можете выделить динамическую память:

     #include <stdlib.h> #include <stdio.h> #include <string.h> const char* hello(char* name) { char* greeting = malloc(100); snprintf("Hello, %s!\n", 100, name) printf("%s\n", greeting); return greeting; } 

    Но это только часть битвы, потому что теперь у вас есть утечка памяти. Вы можете подключить это с помощью другого вызова ctypes на free ().

    … или гораздо лучший подход – прочитать официальную привязку C к python (python 2.x по адресу http://docs.python.org/2/c-api/ и python 3.x по адресу http: / /docs.python.org/3/c-api/ ). Попросите свою C-функцию создать объект строки python и вернуть его обратно. Это будет мусор, собранный python автоматически. Поскольку вы пишете сторону C, вам не нужно играть в игру ctypes.

    …редактировать..

    Я не компилировал и не тестировал, но я думаю, что это .py будет работать:

     import ctypes # define the interface hello = ctypes.cdll.LoadLibrary('./hello.so') # find lib on linux or windows libc = ctypes.CDLL(ctypes.util.find_library('c')) # declare the functions we use hello.hello.argtypes = (ctypes.c_char_p,) hello.hello.restype = ctypes.c_char_p libc.free.argtypes = (ctypes.c_void_p,) # wrap hello to make sure the free is done def hello(name): _result = hello.hello(name) result = _result.value libc.free(_result) return result # do the deed print hello("Frank") 

    Вот что происходит. И почему это ломается. Когда вызывается hello (), указатель стека C перемещается вверх, освобождая место для любой памяти, необходимой вашей функции. Наряду с некоторыми служебными вызовами функций все ваши местные функции функций управляются там. Таким образом, static char greeting[100] означает, что для этой строки используется 100 байт увеличенного стека. Вы, чем использовать некоторые функции, которые управляют этой памятью. Поместите указатель на стек в приветственную память. И затем вы возвращаетесь с вызова, и в этот момент указатель стека возвращается в исходное положение до позиции вызова. Таким образом, эти 100 байт, которые были в стеке на время вашего вызова, по существу, снова используются для захвата, так как стека еще больше манипулируют. Включая поле адреса, указывающее на это значение и возвращаемое вами. В этот момент, кто знает, что с ним происходит, но он, вероятно, установлен на ноль или какое-то другое значение. И когда вы пытаетесь получить к нему доступ, как будто это все еще жизнеспособная память, вы получаете segfault.

    Чтобы обойти, вам нужно каким-то образом управлять этой памятью. Вы можете использовать функцию alloc памяти в куче, но вам нужно будет убедиться, что она станет free() позже на вашей привязке. ИЛИ, вы можете написать свою функцию, чтобы язык привязки передавал ей глюк памяти, который будет использоваться.

    Python - лучший язык программирования в мире.