最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python ctypes: reading a string array - Stack Overflow

programmeradmin1浏览0评论

With python ctypes, how can I read a NUL-terminated array of NUL-terminated strings, e.g. ghostscript's gs_error_names ?

I know how to get the first value:

from ctypes import *
from ctypes.util import find_library

gs = CDLL(find_library("gs"))
print(c_char_p.in_dll(gs, 'gs_error_names').value)

I also know how to get a fixed number of values:

print(list((c_char_p * 10).in_dll(gs, 'gs_error_names')))

But how can I read all values until the end of the array?

With python ctypes, how can I read a NUL-terminated array of NUL-terminated strings, e.g. ghostscript's gs_error_names ?

I know how to get the first value:

from ctypes import *
from ctypes.util import find_library

gs = CDLL(find_library("gs"))
print(c_char_p.in_dll(gs, 'gs_error_names').value)

I also know how to get a fixed number of values:

print(list((c_char_p * 10).in_dll(gs, 'gs_error_names')))

But how can I read all values until the end of the array?

Share Improve this question asked Feb 8 at 1:51 mara004mara004 2,34213 silver badges30 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 0
from ctypes import *
from ctypes.util import find_library

gs = CDLL(find_library("gs"))
error_names_ptr = cast(gs.gs_error_names, POINTER(c_char_p))
error_names = []
i = 0
while val := error_names_ptr[i]:
    error_names.append(val)
    i += 1
print(error_names)

The key was to access the attribute directly and cast(), rather than using in_dll(), which segfaults.

How the global variable is declared matters. A char* is exposed as the address of a pointer that points to the array. A char[] is exposed as the address of the first element of the array.

Working example (Windows export syntax):

// Note C string constants have an additional nul added,
// So this is double nul-terminated.
__declspec(dllexport)
const char *data1 = "abc\0def\0ghi\0jkl\0";

// Also true if the array is unsized, double-nul terminated.
__declspec(dllexport)
const char data2[] = "abc\0def\0ghi\0jkl\0";

Reading each list of nul-terminated strings in Python

import ctypes as ct

dll = ct.CDLL('./test')
data1 = ct.POINTER(ct.c_char).in_dll(dll, 'data1')  # unknown length
data2 = (ct.c_char * 17).in_dll(dll, 'data2')  # if length known
data3 = ct.c_char.in_dll(dll, 'data2')  # unknown length

print(data1[:17])  # slice to view multiple bytes
print(data2.raw)   # Known length of 17

# If you don't know the length of char*, convert the
# pointer to a void pointer, the value of which is
# a Python integer that is the pointer address.
p = ct.cast(data1, ct.c_void_p).value
while s := ct.string_at(p):
    print(s)
    p += len(s) + 1

# If you don't know the length of char[], take the
# address of the array.
p = ct.addressof(data2)
while s := ct.string_at(p):
    print(s)
    p += len(s) + 1

Output:

b'abc\x00def\x00ghi\x00jkl\x00\x00'
b'abc\x00def\x00ghi\x00jkl\x00\x00'
b'abc'
b'def'
b'ghi'
b'jkl'
b'abc'
b'def'
b'ghi'
b'jkl'
发布评论

评论列表(0)

  1. 暂无评论