2012-01-26 10 views
18

Estoy tratando de usar esta función en un programa C que debe poder compilar en Linux y Windows. Al principio intenté usar strtok_r, pero luego cuando compilé en Windows, se quejó de que la función no existía y dijo que asumiría que es una función externa, pero luego falló. ¡Luego usé strtok_s y compilé! Luego probé con Linux pero ahora me estoy quejando de que hay una "referencia indefinida a 'strtok_s'".¿Cuál es la diferencia entre strtok_r y strtok_s en C?

¿Es una una función de solo Windows y la otra una función de Linux? ¿Qué puedo hacer para que compile en ambos?

+0

['strtok_r()'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtok_r.html) es POSIX; ['strtok_s()'] (http://msdn.microsoft.com/en-us/library/ftsafwz3.aspx) es Windows. Use plain 'strtok()' que está disponible en todas las implementaciones * (compatible con C89) *. – pmg

+3

El problema es que necesito strtok una cadena mientras strtoking otra cadena, razón por la cual necesito este, ya que guarda el estado. – petranaya

+1

@pmg - a menos que necesite seguridad de desbordamiento de búfer 0 –

Respuesta

8

Ambas funciones son realmente desagradables, expresiones poco intuitivas para analizar cadenas de caracteres, y generalmente no cumplen con los requisitos de su aplicación particular de manera sutil. Incluso más para el strtok normal en el estándar C. Simplemente deséchelos y escriba su propio código para iterar sobre el arreglo char y divídalo según sea necesario. strchr, strspn y strcspn pueden ser útiles para hacerlo o simplemente puede trabajar desde cero en la matriz.

+1

¿Puede explicar un poco más acerca de por qué estas funciones son malas? Me parece más intuitivo que ir de personaje en personaje y buscar cosas. – petranaya

+3

(1) el separador de caracteres se sobrescribe/pierde, por lo que a menos que solo tenga un separador posible, está perdiendo información. (2) múltiples separadores consecutivos son tratados como uno, lo cual tiene sentido si su separador es un espacio en blanco pero no si es una coma, por ejemplo .. –

+3

Tenga en cuenta que seguramente en * algunas * situaciones, la semántica 'strtok' es justo lo que querer y el único problema es la condición de estado (que 'strtok_r' y' strtok_s' fix). Solo descubro que cada vez que trato de usarlos, hay al menos un aspecto de mis necesidades de análisis que no admiten, y resulta más fácil escribir el código directamente. –

4

strtok_r es una versión segura hilo de strtok en sistemas POSIX

strtok_s es una versión segura saturación de búfer de strtok en Windows. El strtok estándar en Windows es seguro para subprocesos, por lo que strtok_s debería ser.

+0

'strtok_r' es parte de POSIX y lo ha sido durante años (¿décadas?) –

+0

@R - Sí, lo siento, no es estándar C, editará –

+0

Todavía creo que la respuesta no es terriblemente útil ya que solo cubre lo que OP (principalmente) ya sabía, no cómo resolver el problema. –

29

strtok_s es simplemente la versión de Windows de strtok_r que es estándar en todos lados.

Una forma (común yo creo) para hacer un portátil de programa cuando se trata de funciones como strtok_s/strtok_r es utilizar el preprocesador:

#if defined(_WIN32) || defined(_WIN64) 
/* We are on Windows */ 
# define strtok_r strtok_s 
#endif 

Como los prototipos y la funcionalidad es la misma, se puede ahora use solo strtok_r.

+0

Esto probablemente se rompería si se compila en cygwin que se reporta a sí mismo como Windows pero tiene interfaces posix como 'strtok_r' ya definidas. Usar algo como '#ifndef HAVE_STRTOK_R' (y detectarlo en los scripts de compilación) sería mejor. –

+0

¡Muy buen consejo si compilas en Visual Studio o Linux! –

+5

@R ..: cygwin en realidad no define '_WIN32' (o' _WIN64') precisamente por esta razón: se usa comúnmente para identificar código que no es unix. Cygwin define '__CYGWIN__' y' __unix__' en su lugar –

8

No tengo suficiente reputación para comentar otras respuestas, así que tendré que proporcionar la mía.

Para hacer frente a esta declaración:

"strtok_s es un desbordamiento de búfer versión segura de strtok en Windows El strtok estándar en ventanas es hilo de seguridad ...."

Esto no es cierto. strtok_s es la versión segura de subprocesos para el compilador de MSVC. strtok no es seguro para subprocesos

Para hacer frente a esta declaración:

"Esto probablemente se rompería si la compilación de cygwin que informa como ventanas, pero tiene las interfaces POSIX como strtok_r ya definido."

Nuevamente, no es cierto. La diferencia es qué compilador usas. Al usar el compilador de Visual C++ de Microsoft, MSVC, la función es strtok_s. Otro compilador, como GNU Compiler Collection, GCC, puede usar una implementación de biblioteca estándar diferente, como strtok_r. Piensa en el compilador, no en la plataforma de destino, al identificar qué función usar.

En mi opinión, la respuesta de Joachim Pileborg es la mejor en esta página. Sin embargo, se necesita una pequeña edición:

#if defined(_WIN32) /* || defined(_WIN64) */ 
#define strtok_r strtok_s 
#endif 

Tanto _WIN32 y _WIN64 son macros predefinidas proporcionadas por el compilador MSVC._WIN64 se define al compilar un objetivo de 64 bits. _WIN32 se define para objetivos de 32 y 64 bits. Este es un compromiso que Microsoft hizo para la compatibilidad con versiones anteriores. _WIN32 se creó para especificar la API de Win32. Ahora debería considerar _WIN32 para especificar la API de Windows, no es específico para un objetivo de 32 bits.

+1

Se equivoca sobre el primer punto: strtok ** es ** seguro para subprocesos en Windows, ya que dos subprocesos distintos pueden usar esa función de forma segura dentro del mismo proceso, incluso si strtok tiene otros problemas como se explica en [otra respuesta] (http://stackoverflow.com/a/16821026/656988) por @JameyKirby. – AntoineL

4

Solo para aclarar. strtok es seguro para subprocesos en Windows. strtok usa una variable TLS para mantener el último puntero de cada hilo. Sin embargo, no puede usar strtok para intercalar el acceso a más de una cadena de tokens por hilo. strtok_r y strtok_s abordan este problema de intercalación al permitir que el usuario mantenga el contexto a través del tercer parámetro. Espero que esto ayude.

Cuestiones relacionadas