2009-01-27 8 views
15

Hace poco me di cuenta de que la función strdup() que he disfrutado utilizando tanto en OS X no es parte de ANSI C, sino parte de POSIX. No quiero volver a escribir todo mi código, así que creo que voy a escribir mi propia función strdup(). No es tan difícil, realmente, es solo un malloc() y un strcpy(). De todos modos, tengo la función, pero ¿qué hago si escribo esta función y la vinculo a mi código, y ya existe en la libc? ¿Mi enlazador o compilador me permitirá básicamente definir mi propia versión de la función, o tengo que darle otro nombre? Sería terriblemente conveniente si hubiera una manera de reutilizar el mismo nombre, de modo que si strcpy() existe en la libc del usuario podrían usar eso, pero si no existiera en su libc, podrían usar mi versión en su lugar, con tan poco cambio de código como sea posible.strdup() función

La versión corta:

a) ¿Qué ocurre cuando escribo mi propia función con el mismo nombre que una función incorporada?

b) ¿Qué puedo hacer para evitar que me pasen cosas malas en plataformas que no tienen strdup() sin volver a escribir todo mi código para no usar strdup(), lo cual es un poco tedioso?

Respuesta

20

Por lo general, solo utiliza un #if para definir la función que desea cuando está bajo un compilador determinado. Si la biblioteca incorporada no define strdup, no hay ningún problema en la definición de usted mismo (por motivos distintos que hacen definirlo en el futuro, tendrá que llevarlo a cabo.)

// Only define strdup for platforms that are missing it.. 
#if COMPILER_XYZ || COMPILER_ABC 
char *strdup(const char *) 
{ 
    // .... 
} 
#endif 
+8

Si se siente ambicioso, incluso podría configurar automake y autoconf para configurar la macro necesaria para probar si necesita definir strdup usted mismo, en lugar de enumerar todos los compiladores y entornos que desea admitir. –

4

a) ¿Qué sucede cuando escribo mi propia función con el mismo nombre que una función incorporada ?

No puede volver a definir una función que ya existe en un archivo de encabezado que está incluyendo. Esto dará como resultado un error de compilación.

b) ¿Qué puedo hacer para evitar las cosas malas que me pasa en las plataformas que no tienen strdup() sin tener que reescribir todo mi código para no utilizar strdup(), que es sólo un poco ¿tedioso?

recomendaría la creación de su propia función de contenedor a strdup, y la sustitución de todas sus llamadas a utilizar la nueva función de contenedor. Por ejemplo:

char *StringDuplicate(const char *s1) 
{ 
#ifdef POSIX 
    return strdup(s1); 
#else 
    /* Insert your own code here */ 
#endif 
} 

Cambio de todas sus llamadas de strdup a StringDuplicate() debe ser un simple operación de búsqueda y reemplazo, por lo que es un enfoque viable. La lógica específica de la plataforma se mantendrá en una única ubicación en lugar de dispersarse por la base de código.

2

FYI: Nunca he visto personalmente un entorno que no definiera strdup().

+1

también me gustaba strdup, hasta que se lo conté a muchachos en ## c en irc.freenode.org. no les gusta, y argumentan que si hay dos líneas simples, garantizadas, ¿por qué uno debería depender de funciones no portátiles? (strdup está en desuso en Windows, y win ce no parece tenerlo) –

+0

msdn dice que uno debería usar _strdup en su lugar. pero de todos modos, creo que leí esas advertencias de depreciación son tonterías :) pero hoy fue una sorpresa para mí ver que strdup en realidad se usa tan ampliamente. –

6

puede utilizar una macro como esta, de esta manera puede usar el nombre anterior, pero el vinculador verá un nombre diferente;

char *my_strdup(const char *s) { 
    char *p = malloc(strlen(s) + 1); 
    if(p) { strcpy(p, s); } 
    return p; 
} 

/* this goes in whatever header defines my_strdup */ 
char *my_strdup(const char *s); 
#define strdup(x) my_strdup(x) 
+0

buena solución, pero debe ajustar el #define de strdup (x) dentro de otros mecanismos de verificación para determinar si necesita ser reemplazado. Si no es así, probablemente desee utilizar libc strdup – Matt

+4

No hay mucho daño en * no * comprobar eso, excepto para posibles optimizaciones. Por cierto, más arriba podría ser más rápido con caching strlen y luego usando memcpy, porque es un elemento intrínseco en muchos compiladores, que termina en una única instrucción de CPU. –

3

También debería considerar evitar la creación de cualquier identificador (incluida una función) que comience con str [a-z]. Si bien esto no está reservado, el estándar C (ISO/IEC 9899: 1999) sección 7.26.11 (futuras instrucciones de la biblioteca) indica "Los nombres de funciones que comienzan con str, mem o wcs y una letra minúscula pueden agregarse a las declaraciones en el encabezado".

6

Como señaló Rob Kennedy, la mejor manera es probar dentro de las secuencias de comandos de construcción si esta función existe o no. Sé que es bastante fácil con la configuración automática, pero probablemente también con otras herramientas de scripts de construcción multiplataforma.

Entonces sólo tiene que colocar en su archivo de cabecera:


#ifndef HAVE_STRDUP 
# ifdef HAVE__STRDUP 
# define strdup _strdup 
# else 
# define strdup my_strdup 
# endif 
#endif 

Si strdup ya existe en la plataforma de destino la versión de libc se utiliza, si no va a utilizar la función de su my_strdup personalizado.

EDITAR: Debería haber agregado una explicación por qué es mejor.

Primero, el compilador no está relacionado con la existencia de una función en la libc. Por ejemplo, tome la función strlcpy. Está presente en FreeBSD pero no en Linux (glibc), aunque ambos usan gcc por defecto. ¿O qué pasa si alguien va a compilar tu código con clang?

En segundo lugar, una comprobación de plataforma (no sé si hay una forma estándar) solo funcionará si agrega explícitamente para cada plataforma que desea admitir el condicional del preprocesador correcto. Entonces, suponiendo que haya dominado la compilación de su aplicación en OSX y Win32 y quiera compilarla ahora en Linux, tendrá que pasar por todos los condicionales del preprocesador para ver si funcionan para Linux. Quizás también quieras apoyar FreeBSD, OpenBSD, etc. Mismo trabajo de nuevo. Con una prueba en sus scripts de construcción, puede compilar sin ningún trabajo adicional.

-2

Si alguien más lee esto: No use strdup de plataforma() incluso si está disponible, y no pierda tiempo/esfuerzo con autoconf/automake solo para usarlo. En serio, qué tan difícil es esto:

char* mystrdup(const char* str) 
{ 
return strcpy(malloc(strlen(str) + 1),str); 
} 

¿Esto realmente garantiza #ifdefs? ¿Verificación de compilador? BESO.

+16

¿Qué sucede si malloc falla? –

Cuestiones relacionadas