2011-05-09 12 views
19

std::strlen no maneja las cadenas c que no están \ 0 terminadas. ¿Hay una versión segura de esto?¿Hay una versión segura de strlen?

PD Sé que en C++ std :: string se debe utilizar en lugar de c strings, pero en este caso mi cadena se almacena en una memoria compartida.

EDITAR

Ok, tengo que añadir alguna explicación.

Mi aplicación está obteniendo una cadena de una memoria compartida (que es de cierta longitud), por lo tanto, podría representarse como una matriz de caracteres. Si hay un error en la biblioteca al escribir esta cadena, entonces la cadena no terminará en cero, y el strlen podría fallar.

+15

... entonces, ¿qué _desea_ terminar la cadena? Si no hay un terminador de cadena y no hay otra forma de inferir la longitud de la cadena de la cadena misma, necesita almacenar la longitud en una variable separada en alguna parte. –

+9

Si no conoce la longitud y no tiene forma de saber la longitud, entonces no puede determinar la longitud. –

+3

¿Cuánto dura un trozo de cuerda? Dos veces la distancia de un extremo al medio. – Johnsyweb

Respuesta

5

Si define un c-cadena como

char* cowSays = "moo"; 

entonces autmagically obtiene el '\ 0' al final y strlen volvería 3. Si la definimos así:

char iDoThis[1024] = {0}; 

obtienes un búfer vacío (y una matriz de caracteres, todos los cuales son caracteres nulos). A continuación, puede completarlo con lo que desee, siempre que no exceda la longitud del búfer. Al principio strlen devolvería 0, y una vez que haya escrito algo, también obtendría el número correcto de strlen.
También puede hacer esto:

char uhoh[100]; 
int len = strlen(uhoh); 

pero eso sería malo, porque no tiene idea de lo que está en esa matriz. Podría golpear un carácter nulo que quizás no. El punto es que el carácter nulo es el estándar definido forma de declarar que la cadena ha finalizado.
No tener un carácter nulo significa por definición que la cadena no está terminada. Cambiar eso romperá el paradigma de cómo funciona la cuerda. Lo que quieres hacer es inventar tus propias reglas. C++ le permitirá hacerlo, pero tendrá que escribir mucho código usted mismo.

EDITAR Desde su información recién agregado, lo que quiere hacer es un bucle sobre la matriz y comprobar si el carácter nulo con la mano. También debe hacer una validación si está esperando caracteres ASCII solamente (especialmente si está esperando caracteres alfanuméricos). Esto supone que conoce el tamaño máximo. Si no es necesario para validar el contenido de la cadena entonces se podría utilizar uno de los strnlen familia de funciones: http://msdn.microsoft.com/en-us/library/z50ty2zh%28v=vs.80%29.aspx
http://linux.about.com/library/cmd/blcmdl3_strnlen.htm

+4

Gracias. Estaba buscando strnlen –

+6

@VJo: como 'strnlen' no es C o C++ estándar, es posible que prefiera' memchr' (con una comprobación de nulo y una resta del puntero). O quizás no te importe dado que 'strnlen' está en Windows y Posix. –

+1

@Steve No sabía que no es estándar, pero como es posix, es lo suficientemente bueno para mí (estoy usando Linux). Supongo que también es lo suficientemente bueno para las personas que programan en Windows, ya que está ahí, –

11

Las cadenas C que no tienen terminación nula no son cadenas en C, simplemente son matrices de caracteres y no hay forma de encontrar su longitud.

+2

Ok, pero ¿hay una alternativa a std :: strlen que sea segura? –

+3

@VJo ¿Qué parte de "no hay forma de encontrar su longitud" no entendiste? –

+7

@unapersson: dado que el usuario significa "seguro" en el sentido poco ortodoxo de la palabra "seguro" utilizado por funciones de cadena "seguras" como 'strlcpy', lo que dices no es verdad. Bueno, es cierto pero no relevante ya que el interlocutor no pregunta cómo encontrar la "longitud" de algo sin un terminador nulo, pregunta cómo encontrar la longitud si tiene una, y no falla si no lo hace. Uno podría conocer la longitud del búfer, pero no saber si contiene un byte nulo, y * es * posible descubrir cuál y (si es una cadena) la longitud. –

0

Usted tendrá que codificar la cadena. Por ejemplo:

struct string 
{ 
    size_t len; 
    char *data; 
} __attribute__(packed); 

A continuación, puede aceptar cualquier arreglo de caracteres si conoce la primera sizeof (size_t) bytes de la posición de memoria compartida es el tamaño de la matriz de caracteres. Se pone complicado cuando quieres encadenar matrices de esta manera.

Es mejor confiar en que su otro extremo termine sus cadenas o despliegue su propio strlen que no quede fuera de los límites del segmento de memoria compartida (siempre que sepa al menos el tamaño de ese segmento).

3

Obtenga una mejor biblioteca, o verifique la que tiene; si no puede confiar en que su biblioteca hará lo que dice que hará, entonces ¿cómo espera el programa h%^&?

Ésta es decir, suponiendo que conoce la longitud de la buiffer reside la cadena, ¿qué pasa con

buffer[-1+sizeof(buffer)]=0 ; 
x = strlen(buffer) ; 
  • hacen buffer mayor de lo necesario y, a continuación, puede probar la lib.

    assert(x<-1+sizeof(buffer)); 
    
+3

. Bueno, el tipo que escribió esa biblioteca ya no está aquí, y fue muy descuidado. Encontré un error que causó que strlen fallara. De todos modos, strnlen está haciendo lo que necesito –

14

Ha añadido que la cadena está en la memoria compartida. Eso es garantizado legible y de tamaño fijo. Por lo tanto, puede usar size_t MaxPossibleSize = startOfSharedMemory + sizeOfSharedMemory - input; strnlen(input, MaxPossibleSize) (tenga en cuenta el n adicional en strnlen).

Esto devolverá MaxPossibleSize si no hay \0 en la memoria compartida después de input, o la longitud de la cadena, si la hay. (La longitud de la cadena máxima posible es, por supuesto MaxPossibleSize-1, en caso de que el último byte de la memoria compartida es la primera \0)

+0

Sí, eso es lo que hice. Gracias por la respuesta –

0

Si usted necesita para obtener el tamaño de memoria compartida, trate de usar

// get memory size 
struct shmid_ds shm_info; 
size_t shm_size; 
int shm_rc; 
if((shm_rc = shmctl(shmid, IPC_STAT, &shm_info)) < 0) 
    exit(101); 
shm_size = shm_info.shm_segsz; 

lugar de usar strlen puede usar shm_size - 1 si está seguro de que está terminado en nulo. De lo contrario, puede anularlo por datos [shm_size - 1] = '\ 0'; luego use strlen (datos);

6
size_t safe_strlen(const char *str, size_t max_len) 
{ 
    const char * end = (const char *)memchr(str, '\0', max_len); 
    if (end == NULL) 
     return max_len; 
    else 
     return end - str; 
} 
+1

Puede cambiar el nombre de la función para que coincida con esto: http://linux.about.com/library/cmd/blcmdl3_strnlen.htm – harper

0

una solución sencilla:

buff[BUFF_SIZE -1] = '\0' 

OFC esto no le dirá si la cadena originalmente fue exactamente BUFF_SIZE-1 de largo o se termina simplemente no ... por lo que necesita para que la lógica Xtra .

0

¿Qué hay de esta pepita portátil:

int safeStrlen(char *buf, int max) 
{ 
    int i; 
    for(i=0;buf[i] && i<max; i++){}; 
    return i; 
} 
0

Como ya se ha dicho Neil Butterworth en su respuesta anterior: C-Secuencias que no se termina con un carácter \ 0, no son C-Strings!

La única posibilidad que tiene es escribir un Adaptador inmutable o algo que cree una copia válida de la C-String con un carácter de terminación \ 0. Por supuesto, si la entrada está mal y hay un C-String definido como:

char cstring[3] = {'1','2','3'}; 

de hecho se traducirá en un comportamiento inesperado, porque no puede haber algo así como [email protected]\0 en la memoria ahora. Entonces el resultado de strlen() por ejemplo ahora es 6 y no 3 como se esperaba.

El siguiente método muestra cómo crear una caja de seguridad C-String en todo caso:

char *createSafeCString(char cStringToCheck[]) { 
    //Cast size_t to integer 
    int size = static_cast<int>(strlen(cStringToCheck)) ; 
    //Initialize new array out of the stack of the method 
    char *pszCString = new char[size + 1]; 
    //Copy data from one char array to the new 
    strncpy(pszCString, cStringToCheck, size); 
    //set last character to the \0 termination character 
    pszCString[size] = '\0'; 
    return pszCString; 
} 

Esto asegura que si se manipula el C-String para no escribir en la memoria de otra cosa.

Pero esto no es lo que quería. Lo sé, pero no hay otra manera de alcanzar la longitud de una matriz de caracteres sin terminación. Esto ni siquiera es un enfoque. Simplemente asegura que incluso si el usuario (o Dev) está insertando ***** para funcionar bien.

Cuestiones relacionadas