2008-09-28 15 views
5

Ich habe ein Problem mit scandir(): Die Manpage enthält das als Prototyp:Manpage scandir() Prototyp Seltsamkeit

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

Deshalb habe ich dies:

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

Und hier ist der Aufruf :

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

Schließlich sagt der Compiler dies:

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

Compiler ist gcc-4.3.2, mein CFLAGS sind wie folgt:

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

Was ist die Bedeutung dieser Warnung? Die Deklaration von RubyCompare sieht für mich korrekt aus und neben der Warnung funktioniert der Code vollständig.

Antwort

5

Tatsächlich gibt es keine solche Einschränkung, dass Sie keinen Zeiger auf eine Inline-Funktion übergeben können. Das inline-Schlüsselwort dient nur als Hinweis für den Compiler, Aufrufe einzubinden, wenn es möglich ist.

Das Problem ist, dass die Manpage für scandir() ein wenig irreführend ist. Der Prototyp für den 4. Parameter ist tatsächlich int (* cmp) (const void *, const void *).

Daher müssen Sie den Code ändern, wie so:

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

Ich bin nicht wirklich sicher, warum Sie diese Funktion schreiben, aber, weil Sie die mitgelieferte verwenden können AlphaSort Funktion vergleichen:

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

Nun gut, schrieb ich meine eigene Version, weil die Die Manpage war mit der Portabilität von alphasort() ebenfalls irreführend. Mit alphasort() funktioniert es, komisch, dass ich es nie ausprobiert habe. ;) – unexist

+0

Dies führt zu einer Warnung, weil das const-Qualifikationsmerkmal aus den void-Argumenten entfernt wird. Gibt es einen Weg dahin? – TartanLlama

+0

@TartanLiama: Ich weiß nicht, wie Sie diese Warnung bekommen, ich kann es nicht reproduzieren. Es ändert nicht * a oder * b. – Chris

1

Sie geben ihm einen Zeiger auf eine Inline-Funktion? Das macht keinen Sinn, eigentlich wundere ich mich, dass es sogar nur mit einer Warnung kompiliert.

BEARBEITEN: Chris oben ist richtig, das Inline-Schlüsselwort wird einfach still ignoriert, wenn es keinen Sinn macht/nicht anwendbar ist.

3

Dieser Prototyp wurde in der letzten Version von GNU libc geändert, um den POSIX-Standard widerzuspiegeln.

Wenn Sie Code haben, die Sie auf den alten und den neuen Code arbeiten wollen, dann verwenden Sie das __GLIBC_PREREQ Makro so etwas wie

#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

Das ist der Weg zu gehen, nur dass die Reihenfolge der Deklarationen falsch ist, für '#ifdef USE_SCANDIR_VOIDPTR' sollte es' static int RubyCompare (const void * a, const void * b) 'sein – freethinker