Pasar strings terminadas en NULL a bibliotecas C

Si uno quiere un módulo de extensión que necesita pasar una string terminada en NULL a una biblioteca C. Veamos cómo hacerlo con la implementación de strings Unicode de Python. Las bibliotecas C tienen muchas funciones que operan en strings terminadas en NULL declaradas como type char *.

El código que se proporciona a continuación tiene una función C que ilustraremos y probaremos el problema. La función C ( Código #1 ) simplemente imprime la representación hexadecimal de caracteres individuales para que las strings pasadas se puedan depurar fácilmente.

Código #1:

void print_chars(char *s)
{
    while (*s)
    {
        printf("%2x ", (unsigned char) *s);
        s++;
    }
    printf("\n");
}
  
print_chars("Hello");

Producción :

48 65 6c 6c 6f

 
Para llamar a dicha función C desde Python, hay pocas opciones. Lo primero es que: se puede restringir para operar solo en bytes usando el código de conversión «y» PyArg_ParseTuple()como se muestra en el código a continuación.

Código #2:

static PyObject * py_print_chars(PyObject * self, PyObject * args)
{
    char * s;
    if (! PyArg_ParseTuple(args, "y", &s))
    {
        return NULL;
    }
    print_chars(s);
    Py_RETURN_NONE;
}

 
Veamos cómo funciona la función resultante y cómo se rechazan los bytes con bytes NULL incrustados y strings Unicode.

Código #3:

print (print_chars(b'Hello World'))
  
print ("\n", print_chars(b'Hello\x00World'))
  
print ("\n", print_chars('Hello World'))

Producción :

48 65 6c 6c 6f 20 57 6f 72 6c 64

Traceback (most recent call last):
File "", line 1, in 
TypeError: must be bytes without null bytes, not bytes

Traceback (most recent call last):
File "", line 1, in 
TypeError: 'str' does not support the buffer interface

 
Si desea pasar strings Unicode en su lugar, use el código de formato «s» PyArg_ParseTuple()como se muestra a continuación.

Código #4:

static PyObject *py_print_chars(PyObject *self, PyObject *args)
{
    char *s;
    if (!PyArg_ParseTuple(args, "s", &s))
    {
        return NULL;
    }
    print_chars(s);
    Py_RETURN_NONE;
}

 
El uso del código anterior ( código #4 ) convertirá automáticamente todas las strings a una codificación UTF-8 terminada en NULL. Como se muestra en el siguiente código.

Código #5:

print (print_chars('Hello World'))
  
# UTF-8 encoding
print ("\n", print_chars('Spicy Jalape\u00f1o'))
   
print ("\n", print_chars('Hello\x00World'))
   
print ("\n", print_chars(b'Hello World'))

Producción :

48 65 6c 6c 6f 20 57 6f 72 6c 64

53 70 69 63 79 20 4a 61 6c 61 70 65 c3 b1 6f

Traceback (most recent call last):
File "", line 1, in 
TypeError: must be str without null characters, not str

Traceback (most recent call last):
File "", line 1, in 
TypeError: must be str, not bytes

 
Si trabaja con a PyObject *y no puede usar PyArg_ParseTuple(), el siguiente código explica cómo verificar y extraer una char *referencia adecuada, tanto de un objeto de bytes como de string.

Código #6: Conversión de bytes

// Some Python Object
PyObject *obj;
  
// Conversion from bytes 
{
    char *s;
    s = PyBytes_AsString(o);
    if (!s)
    {
        /* TypeError already raised */
        return NULL; 
    }
    print_chars(s);
}

 
Código #7: Conversión a bytes UTF-8 de una string

{
  
    PyObject *bytes;
    char *s;
  
    if (!PyUnicode_Check(obj))
    {
        PyErr_SetString(PyExc_TypeError, "Expected string");
        return NULL;
    }
  
    bytes = PyUnicode_AsUTF8String(obj);
    s = PyBytes_AsString(bytes);
    print_chars(s);
    Py_DECREF(bytes);
}

Ambas conversiones de código garantizan datos terminados en NULL, pero no hay verificación de bytes NULL incrustados en otros lugares dentro de la string. Eso debe verificarse si es importante.

Nota: Hay una sobrecarga de memoria oculta asociada con el uso del código de formato «s» PyArg_ParseTuple()que es fácil de pasar por alto. Al escribir un código que utiliza esta conversión, se crea una string UTF-8 y se adjunta de forma permanente al objeto de string original que, si contiene caracteres que no son ASCII, hace que el tamaño de la string aumente hasta que se recopile como basura.

Código #8:

import sys
s = 'Spicy Jalape\u00f1o'
print ("Size : ", sys.getsizeof(s))
  
# passing string
print("\n", print_chars(s))
  
# increasing size
print ("\nSize : ", sys.getsizeof(s))

Producción :

Size : 87

53 70 69 63 79 20 4a 61 6c 61 70 65 c3 b1 6f

Size : 103

Publicación traducida automáticamente

Artículo escrito por manikachandna97 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *