tags:

views:

447

answers:

3

I have a problem with scandir(): The manpage contains this as prototype:

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

Therefore I have this:

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

And here's the call:

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

Finally the compiler says this:

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

Compiler is gcc-4.3.2, my CFLAGS are following:

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

What is the meaning of this warning? The declaration of RubyCompare looks correct for me and besides the warning the code works completely.

+1  A: 

You're giving it a pointer to an inline function? That doesn't make sense, actually I wonder that it even compiles with only a warning.

EDIT: Chris above is right, the inline keyword is just ignored silently when it doesn't make sense / is not applicable.

jkramer
+5  A: 

Actually, there's no such constraint that you can't pass a pointer to an inline function. The inline keyword serves only as a hint to the compiler to inline calls when it can.

The problem is that the manpage for scandir() is a little misleading. The prototype in for the 4th parameter is actually int (*cmp)(const void *, const void *).

Therefore you need to change the code like so:

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

I'm not actually sure why you're writing this function, though, because you can use the provided alphasort compare function:

num = scandir(buf, &entries, NULL, alphasort);
Chris Young
Well right, I wrote my own version because the manpage was misleading with the portability of alphasort() as well. With alphasort() it works, funny that I never tried it. ;)
unexist
A: 

This prototype has actually changed in recent version of GNU libc to reflect POSIX standard.

If you have code that you want to work on both old and new code, then use the __GLIBC_PREREQ macro something like

#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 struct dirent **a,  const struct dirent **b)
#else 
 static int RubyCompare(const void *a,  const void *b)
#endif

...

Mark Borgerding