Pasar una lista de cadenas de python/ctypes a la función C esperando char **

3 minutos de lectura

avatar de usuario
joakim hove

Tengo una función C que espera una lista de cadenas terminadas en 0 como entrada:

void external_C( int length , const char ** string_list) { 
   // Inspect the content of string_list - but not modify it.
} 

Desde python (con ctypes) me gustaría llamar a esta función en función de una lista de cadenas de python:

def call_c( string_list ):
    lib.external_C( ?? )

call_c( ["String1" , "String2" , "The last string"])

¿Algún consejo sobre cómo construir la estructura de datos en el lado de Python? Observe que le garantizo que la función C NO alterará el contenido de las cadenas en string_list.

Saludos

joaquín

  • ¿Cómo sabe la función C que ha llegado al final de la secuencia de const char *?

    – habito

    16 de agosto de 2010 a las 15:26

  • Bien; en general no sabe por supuesto. Mi intención era terminarlo con un NULL, alternativamente, puedo pasar una longitud y el puntero (char **): tengo control total sobre la biblioteca C en cuestión. Joaquín

    – Joakim Hove

    16 de agosto de 2010 a las 15:32

  • Si no lo sabe, es bastante inútil. Necesitas contarlo de alguna manera, y contar a nosotros para que podamos darle un código que funcione.

    – habito

    16 de agosto de 2010 a las 15:32


  • BIEN BIEN; No pensé que eso fuera tan importante. De todos modos, ahora he cambiado la definición de la función C para que tome un argumento de longitud como primer argumento.

    – Joakim Hove

    16 de agosto de 2010 a las 15:43

  • Lo siento, ¿cuáles deberían ser los tipos de argumentos para external_C?

    – mm_

    1 de diciembre de 2020 a las 23:38

def call_c(L):
    arr = (ctypes.c_char_p * len(L))()
    arr[:] = L
    lib.external_C(len(L), arr)

  • Tenga en cuenta que en Python 3.x, las cadenas son Unicode de forma predeterminada, por lo que debe convertir sus cadenas en bytes a través de s.encode('utf-8') o bytes(s, 'utf-8') (o cualquier codificación que desee usar que no sea UTF-8).

    – corwin.ámbar

    24 de diciembre de 2018 a las 15:55

  • Sería bueno incorporar este ^ en la respuesta

    – ben26941

    20 de enero de 2020 a las 15:52

avatar de usuario
usuario422005

Muchísimas gracias; eso funcionó a las mil maravillas. También hice una variación alternativa como esta:

def call_c( L ):
    arr = (ctypes.c_char_p * (len(L) + 1))()
    arr[:-1] = L
    arr[ len(L) ] = None
    lib.external_C( arr )

Y luego, en la función C, iteré a través de la lista (char **) hasta que encontré un NULL.

usando ctypes

crear una lista de vencimientos (cadenas)

expiries = ["1M", "2M", "3M", "6M","9M", "1Y", "2Y", "3Y","4Y", "5Y", "6Y", "7Y","8Y", "9Y", "10Y", "11Y","12Y", "15Y", "20Y", "25Y", "30Y"]

Lógica para enviar matriz de cadenas

convertir una matriz de cadenas en una matriz de bytes haciendo un bucle en la matriz

 expiries_bytes = []
    for i in range(len(expiries)):
        expiries_bytes.append(bytes(expiries[i], 'utf-8'))

Tipos lógicos para iniciar un puntero con una longitud de matriz

expiries_array = (ctypes.c_char_p * (len(expiries_bytes)+1))()

asignando la matriz de bytes en el puntero

expiries_array[:-1] = expiries_bytes

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad