передача строк Python через Cython в C - PullRequest
5 голосов
/ 21 ноября 2011

Я пытаюсь написать модуль с некоторыми частями C и Python.Я использую cython для преодоления разрыва.

Я хочу сохранить свои (очень длинные) строковые константы в python, потому что синтаксис намного лучше:

const char long_string = "\npart of string\n"
  "next part\n"
  "last part\n";

против:

long_string = """
part of string
next part
last part
"""

(строки намного длиннее и сложнее - в той степени, в которой я не хочу добавлять и удалять " s и \n" s каждый раз, когда я хочу редактироватьэто с подсветкой синтаксиса. На самом деле это ядра openCL.)

Мне нужно иметь возможность превратить их в строки c с помощью Cython, и в соответствии с документацией Мне просто нужно это:

cdef bytes py_bytes = py_string.encode()
cdef char* c_string = py_bytes

и без ручного управления памятью, c_string будет работать, пока я сохраняю ссылку на py_bytes.

Однако я не могу заставить это работать спростой тест printf.Вот мой файл Cython:

cdef extern from "stdio.h":
  printf(char* string)

def go():
  py_string = """
a complicated string
with a few
newlines.
"""

  cdef bytes py_bytes = py_string.encode()

  cdef char* c_string = py_bytes

  printf(c_string)

  print "we don't get this far :("

, который при компиляции во время выполнения с использованием pyximport дает следующий вывод на терминал перед segfaulting:

a complicated string
with a few
newlines.
Segmentation fault: 11

Теперь я проверил, чтоCython фактически помещает в файл c и пробовал его в файле vanilla C, где он не segfault:

#include "stdio.h"

static char __pyx_k_1[] = "\na complicated string\nwith a few\nnewlines.\n";

int main(void) {
  void* output = printf(__pyx_k_1);
  if (!output) {
    printf("apparently, !output.");
  }
}

, чтобы быть понятным, cython генерирует код, который ловит выходные данныеprintf и тесты на "не то".тип переменной - PyObject*.

. Мое единственное предположение здесь состояло в том, что строка была неправильно завершена, поэтому printf просто переносит ее конец и вызывает ошибку segfault, но, поскольку это не такслучиться в моем чистом тесте c, я полностью в замешательстве.

Итак, мой актуальный вопрос: как мне действительно передать c-строку в c-код из cython?Ответы, указывающие на более простой способ решить реальную проблему, которую я пытаюсь решить наверху, также очень приветствуются:)

1 Ответ

8 голосов
/ 21 ноября 2011

Импорт printf из libc.stdio исправляет проблему для меня:

from libc.stdio cimport printf

def go():
    py_string = """
a complicated string
with a few
newlines.
"""

    cdef bytes py_bytes = py_string.encode()
    cdef char* c_string = py_bytes
    printf(c_string)

    print "we actually got this far! :)"

Ошибка в объявлении printf.Это должно быть, как stdio.pxd списки,

cdef extern from *:
    ctypedef char const_char "const char"

int printf(const_char *, ...)

, тогда как ваша версия неявно object printf(char *);тип возвращаемого значения по умолчанию - объект Python, а не int, как в C. Получение правильного объявления отключает попытку Cython Py_XDECREF возвращаемого значения из printf.

(кстати, в вашем "vanilla"«Проблема C, вы не должны приводить возвращаемое значение от printf к void *.)

...