Есть ли способ передать строку python2.7 с нулевым символом в середине (например, foo\0bar
) код C ++ в привязках Swig?
привязки Python C обеспечить две функции: PyString_AsString
а также PyString_AsStringAndSize
, но обе функции возвращают строки с нулевым символом в конце.
Как документы для PyString_AsStringAndSize
скажем, он сохраняет внутренние нулевые символы, если вы не передадите NULL
за length
, Что вы, очевидно, не собираетесь делать (поскольку вы не можете ничего сделать со строкой с внутренними нулевыми символами, если вы не знаете, что это длина).
Он гарантирует нулевой терминатор в конце, хотите ли вы один или нет, но если это неприемлемо, с ним легко разобраться: просто уменьшите длину, которую он возвращает, на единицу.
Так что, если вы не беспокоитесь о потенциальной производительности Python, копирующей буфер, просто чтобы добавить нулевой терминатор, который вам не нужен (в этом случае я бы не волновался — большинство способов создания строк, вы уже собираетесь чтобы иметь терминатор в буфере), здесь не должно быть никаких проблем.
Чтобы доказать это:
#!/usr/bin/env python2.7
from ctypes import *
PyString_AsStringAndSize = pythonapi.PyString_AsStringAndSize
PyString_AsStringAndSize.argtypes = [
py_object, POINTER(POINTER(c_int8)), POINTER(c_ssize_t)]
PyString_AsStringAndSize.restype = c_int
s = 'foo\0bar'
buf = POINTER(c_int8)()
size = c_ssize_t()
res = PyString_AsStringAndSize(s, byref(buf), byref(size))
print res
print size.value
bufa = cast(buf, POINTER(c_int8 * size.value))
print bufa.contents[:size.value]
print repr(''.join(chr(c) for c in bufa.contents[:size.value]))
Выход:
0
7
[102, 111, 111, 0, 98, 97, 114]
'foo\x00bar'
Именно то, что вы хотели, верно?
(А в C ++ вам не придется делать все эти раздражающие вещи, чтобы обойти ctypes
что я сделал, сначала используя int8
вместо char
чтобы он не был слишком умным и не создавал строку, а затем приводил ее к массиву, потому что арифметика указателей не допускается.)
Других решений пока нет …