cfunctionmacros

Using S_ISREG() (and other macros) as parameter to function


I am trying to create a function that will be generally used to determine if a file/directory exists, if it is within a certain path, and if it is of the specified type (S_ISREG, S_ISDIR, ...

Here are the parts of the source pertaining to this question:

int checkExists(const char *name, void *func(int))) {
   struct stat st ;
   int returnValue = DOES_NOT_EXIST ;
   BOOL isInSourceHierarchy, isInTargetHierarchy ;

   if (stat(name, &st) != -1) {
      returnValue = EXISTS ;
      if (memcmp(name, top_dir, strlen(top_dir)))
         returnValue |= IN_SOURCE_STRUCTURE ;
      if (memcmp(name, tgt_dir, strlen(tgt_dir)))
         returnValue |= IN_TARGET_STRUCTURE ;
      if (func != NULL) {
         if (objType == func(st.st_mode))
            returnValue |= RIGHT_TYPE ;
      }
   }

   return returnValue ;
}

. . . 

if (S_ISREG(0)) {} // Yes, I know, I know.  This is for demonstration only.
if (checkExists(old, S_ISREG)) {
   // Do something
 } else { // Old file doesn't exist
   // Do something else
 }

When trying to compile this, I get:

linkStructure.c:642:31: error: ‘S_ISREG’ undeclared (first use in this function)
  642 |          if (checkExists(old, S_ISREG)) {
      |                               ^~~~~~~

As can be seen, there is no complaint about the macro used as designed, of course. So my question is: Is there a way for me to reference the macro in my source like this? Or will I be left to basically emulate the macro in my function? (I suppose I could pass the expected type rather than the function, but for the sake of clarity, I would like to understand this limitation.)


Solution

  • It says S_ISREG is undefined because the preprocessor doesn't ignore the parenthesis. #define FOO() defines FOO(), not FOO.

    Also, your function expects a function pointer as parameter, but macros are compile-time only symbols, you can't take its address.

    But you can just wrap it in a function instead:

    int isReg(int mode)
    {
        return S_ISREG(mode);
    }
    

    Now you can use it as you wanted:

    checkExists(old, isReg);
    

    And you keep the flexibility of your original code.