2010-02-23 20 views
5

Estoy tratando de implementar una versión eqivilent de la función chomp() de perl en C y he encontrado un caso de esquina donde un literal de cadena pasó ya que el argumento causará un error de segmentación (con razón).¿Cómo detectar el paso de un literal de cadena a una función en C?

Ejemplo chomp("some literal string\n");

¿Hay una manera definida en C99 para detectar tiempo o no mi función fue aprobada una cadena literal de modo que pueda return sin intentar NUL a cabo?

char* chomp(char *s) 
{ 
    char *temp = s; 

    if (s && *s) 
    { 
     s += strlen(s) - 1; 
     if (*s == '\n') 
     { 
      *s = '\0'; 
     } 
    } 
    return temp; 
} 
+2

Impar. ¿No debería su compilador evitar que se pase un literal de cadena como un argumento que no está declarado como 'const char *'? –

+0

@ Adam Maras: Eso no es requerido por el estándar. Sin embargo, tratando de modificar el mismo es UB. – dirkgently

+2

Adam Maras: En C simple, los literales de cadena tienen el tipo 'char *', no 'const char *'. – caf

Respuesta

5

¿Hay una manera definida en C99 para detectar si mi función se pasó una cadena literal para que yo pueda regresar sin intentar NUL?

No debe.

Su API no debe intentar distorsionar las cosas para la persona que llama, solo para interrumpirlas más tarde. Si la persona que llama rompe las reglas, debe enterarse en ese momento.

Si la persona que llama pasa una cadena no mutable a una función que espera una mutable, debe segfault. Cualquier otra cosa es un mal diseño.

(Adición: El mejor diseño, por supuesto, sería volver una copia de la cadena que la persona que llama es responsable de liberar.)

+1

¿Existe alguna práctica recomendada que no sea la documentación para alertar a la persona que llama que esto podría ser una posible pérdida de memoria si no 'free()' 'd? – SiegeX

+1

@SiegeX - una cosa que me gusta hacer es incluir alloc en los nombres de las funciones que hacen que 'char * chomp_alloc (const char *);' –

+0

@SiegeX: me gustaría ir con 'error_t chomp (const char * input, char ** out_result) 'yo mismo. Es obvio que hay algo que sale de él que no está ahí para la sintaxis, así que obviamente tienes que liberarlo, y también obtienes un error específico. –

3

Lo ideal es que el chomp cree una nueva cuerda y la devuelva. No hay manera de determinar si se le pasó un literal de cadena o no. De hecho, me gustaría sugerir el uso de la siguiente firma para chomp:

char *chomp(const char *s); /* do not modify input parameters */ 

O bien, puede crear dos funciones diferentes y documentarlos para los clientes: chomp utilizar para los no literales y chompl para las cadenas literales.

+0

¿Existe alguna práctica recomendada además de la documentación para alertar a la persona que llama que esto podría ser una posible pérdida de memoria si no 'free()' 'd? – SiegeX

+0

No exactamente. ¿Cómo sabrá alguna vez cuándo el cliente ha terminado de usar este objeto? Ver la documentación de 'strdup' por ejemplo. – dirkgently

1

Hay una mala manera/muy arriesgado => normalmente cordón literales se almacenan en la sección de datos de solo lectura. De modo que una forma es tratar de escribir en la cadena de destino: si segmentation fault se recibe en signal callback, significa que la cadena es literal y vuelve a la función de prueba con longjmp. Algo así como:

#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h> 
#include <setjmp.h> 

static jmp_buf jbuf; 

static void catch_segv() { 
    longjmp(jbuf, 1); 
} 

int isLiteral(char * ptr) { 
    if (setjmp(jbuf) == 0) 
    return (*ptr = *ptr, 0); 
    else 
    return 1; 
    } 

int main() 
{ 
    char writableString[] = "some writable string"; 

    signal(SIGSEGV, catch_segv); 

    printf("is literal = %d\n", isLiteral(writableString)); 
    printf("is literal = %d\n", isLiteral("read-only string")); 

    return 0; 
} 

Pero dado que el programa de reanudar después de SIGSEGV es algo muy arriesgado y dado que los literales de cadena no siempre se almacenan en la sección de sólo lectura de datos - Esta solución es altamente recomendado para un-producción.

Cuestiones relacionadas