Вы определенно близко!Кажется, есть две проблемы.
Во-первых, нам нужно изменить объявление obj
так, чтобы оно читало, что мы пытаемся создать массив char*
объектов, фиксированных до размера 3. Для этого вам нужнопоставить тип, затем имя переменной и только потом размер массива.Это даст вам желаемый массив char*
в стеке.
Во-вторых, когда вы объявляете char* a, b, c
, только a
является char*
, тогда как b
и c
являются просто char
!Это проясняется в cython во время фазы компиляции, которая выводит для меня следующее предупреждение:
Non-trivial type declarators in shared declaration (e.g. mix of pointers and values). Each pointer declaration should be on its own line.
Поэтому вы должны сделать это вместо этого:
cdef char* obj[3]
cdef char* a
cdef char* b
cdef char* c
a = b'abc'
b = b'1234'
c = b'^&$#%'
obj = [a, b, c]
В качестве примечания выможно минимизировать ввод cdef
, выполнив это для своего кода:
cdef:
char* obj[3]
char* a
char* b
char* c
a = b'abc'
b = b'1234'
c = b'^&$#%'
obj = [a, b, c]
Бонус:
На основе вашего уровня опыта работы с C и указателями вВ общем, я просто покажу более удобный для новичков подход с использованием структур данных C ++.C ++ имеет простые встроенные структуры данных, такие как vector
, что эквивалентно списку Python.Альтернативой C было бы иметь указатель на структуру, обозначающую «массив» triplets
.Затем вы лично отвечаете за управление памятью, используя такие функции, как malloc
, free
, realloc
и т. Д.
Вот кое-что, с чего можно начать;Я настоятельно рекомендую вам самостоятельно следовать некоторым онлайн-учебникам по C или C ++ и адаптировать их к Cython, что после некоторой практики должно быть довольно тривиальным.Я показываю как файл test.pyx
, так и файл setup.py
, который показывает, как вы можете скомпилировать его с поддержкой c ++.
test.pyx
from libcpp.vector cimport vector
"""
While it can be discouraged to mix raw char* C "strings" wth C++ data types,
the code here is pretty simple.
Fixed arrays cannot be used directly for vector type, so we use a struct.
Ideally, you would use an std::array of std::string, but std::array does not
exist in cython's libcpp. It should be easy to add support for this with an
extern statement though (out of the scope of this mini-tutorial).
"""
ctypedef struct triplet:
char* data[3]
cdef:
vector[triplet] obj
triplet abc
triplet xyz
abc.data = ["abc", "1234", "^&$#%"]
xyz.data = ["xyz", "5678", "%#$&^"]
obj.push_back(abc)#pretty much like python's list.append
obj.push_back(xyz)
"""
Loops through the vector.
Cython can automagically print structs so long as their members can be
converted trivially to python types.
"""
for o in obj:
print(o)
setup.py
from distutils.core import setup
from Cython.Build import cythonize
from distutils.core import Extension
def create_extension(ext_name):
global language, libs, args, link_args
path_parts = ext_name.split(".")
path = "./{0}.pyx".format("/".join(path_parts))
ext = Extension(ext_name, sources=[path], libraries=libs, language=language,
extra_compile_args=args, extra_link_args=link_args)
return ext
if __name__ == "__main__":
libs = []#no external c libraries in this case
language = "c++"#chooses c++ rather than c since STL is used
args = ["-w", "-O3", "-ffast-math", "-march=native", "-fopenmp"]#assumes gcc is the compiler
link_args = ["-fopenmp"]#none here, could use -fopenmp for parallel code
annotate = True#autogenerates .html files per .pyx
directives = {#saves typing @cython decorators and applies them globally
"boundscheck": False,
"wraparound": False,
"initializedcheck": False,
"cdivision": True,
"nonecheck": False,
}
ext_names = [
"test",
]
extensions = [create_extension(ext_name) for ext_name in ext_names]
setup(ext_modules = cythonize(
extensions,
annotate=annotate,
compiler_directives=directives,
)
)