2008-09-28 14 views
5

tengo un problema con scandir(): La página de manual contiene esto como prototipo:scandir Página de manual() prototipo rareza

int scandir(const char *dir, struct dirent ***namelist, 
    int (*filter)(const struct dirent *), 
    int (*compar)(const struct dirent **, const struct dirent **)); 

Por lo tanto tengo esto:

static inline int 
RubyCompare(const struct dirent **a, 
    const struct dirent **b) 
{ 
    return(strcmp((*a)->d_name, (*b)->d_name)); 
} 

Y aquí está la llamada :

num = scandir(buf, &entries, NULL, RubyCompare); 

Finalmente el compilador dice esto:

warning: passing argument 4 of ‘scandir’ from incompatible pointer type 

Compiler es gcc-4.3.2, mis CFLAGS son los siguientes:

-Wall -Wpointer-arith -Wstrict-prototypes -Wunused -Wshadow -std=gnu99 

¿Cuál es el significado de esta advertencia? La declaración de RubyCompare me parece correcta y, además de la advertencia, el código funciona por completo.

Respuesta

5

En realidad, no existe tal restricción que no pueda pasar un puntero a una función en línea. La palabra clave en línea sirve solo como una sugerencia para el compilador de las llamadas en línea cuando puede.

El problema es que la página de manual de scandir() es un poco engañosa. El prototipo del 4º parámetro es en realidad int (* cmp) (const void *, const void *).

lo tanto, necesidad de cambiar el código de este modo:

static inline int RubyCompare(const void *a, const void *b) 
{ 
    return(strcmp((*(struct dirent **)a)->d_name, 
        (*(struct dirent **)b)->d_name)); 
} 

No estoy realmente seguro de por qué se está escribiendo esta función, sin embargo, porque se puede utilizar la función de comparación ha proporcionado alphasort:

num = scandir(buf, &entries, NULL, alphasort); 
+0

Pues bien, me escribió mi propia versión debido a que la la página de manual fue engañosa con la portabilidad de alphasort() también. Con alphasort() funciona, es divertido que nunca lo haya intentado. ;) – unexist

+0

Hacer esto me da una advertencia porque descarta el calificador const de los argumentos de vacío. ¿Hay alguna forma de evitar esto? – TartanLlama

+0

@TartanLiama: No sé cómo está recibiendo esa advertencia, no puedo reproducirla. No está modificando * a o * b. – Chris

1

¿Le está dando un puntero a una función en línea? Eso no tiene sentido, en realidad me pregunto si incluso compila con solo una advertencia.

EDIT: Chris arriba es correcto, la palabra clave en línea se ignora silenciosamente cuando no tiene sentido/no es aplicable.

3

Este prototipo ha cambiado realmente en la versión más reciente de GNU libc para reflejar el estándar POSIX.

Si tiene código que desea trabajar en ambos viejo y el nuevo código, a continuación, utilizar la macro __GLIBC_PREREQ algo así como

#define USE_SCANDIR_VOIDPTR 
#if defined(__GLIBC_PREREQ ) 
# if __GLIBC_PREREQ(2,10) 
# undef USE_SCANDIR_VOIDPTR 
# endif 
#endif 

#ifdef USE_SCANDIR_VOIDPTR 
static int RubyCompare(const void *a, const void *b) 
#else 
static int RubyCompare(const struct dirent **a, const struct dirent **b) 
#endif 

...

+0

Esa es la manera de hacerlo, solo que el orden de las declaraciones es incorrecto, para '#ifdef USE_SCANDIR_VOIDPTR', debe ser' static int RubyCompare (const void * a, const void * b) ' – freethinker