Stranezze del prototipo di Manpage scandir ()
Domanda
Ho un problema con scandir () : la manpage lo contiene come prototipo:
int scandir(const char *dir, struct dirent ***namelist,
int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **));
Quindi ho questo:
static inline int
RubyCompare(const struct dirent **a,
const struct dirent **b)
{
return(strcmp((*a)->d_name, (*b)->d_name));
}
Ed ecco la chiamata:
num = scandir(buf, &entries, NULL, RubyCompare);
Alla fine il compilatore dice questo:
warning: passing argument 4 of ‘scandir’ from incompatible pointer type
Il compilatore è gcc-4.3.2 , i miei CFLAGS sono i seguenti:
-Wall -Wpointer-arith -Wstrict-prototypes -Wunused -Wshadow -std=gnu99
Qual è il significato di questo avviso? La dichiarazione di RubyCompare sembra corretta per me e oltre all'avvertimento il codice funziona completamente.
Soluzione
In realtà, non esiste un vincolo tale da non poter passare un puntatore a una funzione incorporata. La parola chiave inline serve solo come suggerimento al compilatore per inlineare le chiamate quando può.
Il problema è che la manpage di scandir () è un po 'fuorviante. Il prototipo per il quarto parametro è in realtà int (* cmp) (const void *, const void *).
Pertanto è necessario modificare il codice in questo modo:
static inline int RubyCompare(const void *a, const void *b)
{
return(strcmp((*(struct dirent **)a)->d_name,
(*(struct dirent **)b)->d_name));
}
In realtà non sono sicuro del motivo per cui stai scrivendo questa funzione, perché puoi utilizzare la funzione di confronto alphasort fornita:
num = scandir(buf, &entries, NULL, alphasort);
Altri suggerimenti
Questo prototipo è stato effettivamente modificato nella recente versione di GNU libc per riflettere lo standard POSIX.
Se si dispone di codice su cui si desidera lavorare sia con il codice vecchio che con quello nuovo, utilizzare la macro __GLIBC_PREREQ in modo simile
#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
...
Gli stai dando un puntatore a una funzione inline? Non ha senso, in realtà mi chiedo che si compili anche solo con un avvertimento.
MODIFICA : Chris sopra ha ragione, la parola chiave incorporata viene ignorata silenziosamente quando non ha senso / non è applicabile.