2008-09-28 6 views
5

J'ai un problème avec scandir(): La page de manuel contient ce que prototype:prototype Manpage scandir() de bizarreries

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

J'ai donc ceci:

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

Et voici l'appel :

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

Enfin le compilateur dit ceci:

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

compilateur est gcc-4.3.2, mes CFLAGS suivent:

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

Quelle est la signification de cet avertissement? La déclaration de RubyCompare me semble correcte et en plus de l'avertissement le code fonctionne complètement.

Répondre

5

En fait, il n'y a pas une telle contrainte que vous ne pouvez pas passer un pointeur à une fonction en ligne. Le mot-clé inline sert uniquement d'indication au compilateur pour les appels en ligne lorsqu'il le peut.

Le problème est que la page de manuel pour scandir() est un peu trompeuse. Le prototype du 4ème paramètre est actuellement int (* cmp) (const void *, const void *).

Par conséquent, vous devez modifier le code comme ceci:

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

Je ne suis pas vraiment sûr de savoir pourquoi vous écrivez cette fonction, cependant, parce que vous pouvez utiliser la fonction de comparaison fourni alphasort:

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

bien droit, j'ai écrit ma propre version parce que la manpage était trompeur avec la portabilité d'alphasort() aussi bien. Avec alphasort() ça marche, marrant que je ne l'ai jamais essayé. ;) – unexist

+0

Cela me donne un avertissement car il est en train de supprimer le qualificatif const des arguments void. Y a-t-il un moyen de contourner ceci? – TartanLlama

+0

@TartanLiama: Je ne sais pas comment vous obtenez cet avertissement, je ne peux pas le reproduire. Il ne modifie pas * a ou * b. – Chris

1

Vous lui donnez un pointeur vers une fonction en ligne? Cela n'a pas de sens, en fait je me demande même s'il compile avec seulement un avertissement. : Chris ci-dessus a raison, le mot-clé inline est juste ignoré silencieusement quand il n'a pas de sens/n'est pas applicable.

3

Ce prototype a été modifié dans la version récente de GNU libc pour refléter la norme POSIX.

Si vous avez du code que vous voulez travailler à la fois ancien et le nouveau code, puis utilisez la macro __GLIBC_PREREQ quelque chose comme

#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

C'est le chemin à suivre, juste que l'ordre des déclarations est faux, pour '#ifdef USE_SCANDIR_VOIDPTR', il devrait être' static int RubyCompare (const void * a, const void * b) ' – freethinker