Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manpage scandir() prototype weirdness

Tags:

c

manpage

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.

like image 600
unexist Avatar asked Sep 28 '08 17:09

unexist


3 Answers

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);
like image 111
Chris Young Avatar answered Nov 04 '22 20:11

Chris Young


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

...

like image 21
Mark Borgerding Avatar answered Nov 04 '22 20:11

Mark Borgerding


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.

like image 1
jkramer Avatar answered Nov 04 '22 20:11

jkramer