Search code examples
clinuxgccglibcgnu-coreutils

Where/how is xstrtoul() defined?


I was looking through the code for ls.c and noticed a call to xstrtoul(). I wanted to find out where exactly was this useful function defined. This led me to xstrtol.h, which has the following snippet:

# define _DECLARE_XSTRTOL(name, type) \
  strtol_error name (const char *, char **, int, type *, const char *);
_DECLARE_XSTRTOL (xstrtol, long int)
_DECLARE_XSTRTOL (xstrtoul, unsigned long int)
_DECLARE_XSTRTOL (xstrtoimax, intmax_t)
_DECLARE_XSTRTOL (xstrtoumax, uintmax_t)

If I understand this correctly, the resulting function prototype after the preprocessor pass would be:

strtol_error xstrtoul (const char *, char **, int, unsigned long int *, \
                                                                   const char *);

Yet, the only related function defined in xstrtol.c is __xstrtol(), which has the following signature:

strtol_error
__xstrtol (const char *s, char **ptr, int strtol_base,
           __strtol_t *val, const char *valid_suffixes)

My guess is that somehow, the compiler is mapping multiple instances of this function each time with another name substituted for __xstrtol and another type for __strtol_t. But I don't understand where/how this is done. (There is only a #define for each of those two at the top of xstrtol.c).


Solution

  • OK, the xstrtol.c file is where the function is really defined, but this source file is included into other source files, acting like a C++ function template, to generate functions with slightly different names and behavior.

    Look at xstrtoul.c. It actually includes xstrtol.c but defines several preprocessor symbols to modify the template function generation:

    #define __strtol strtoul
    #define __strtol_t unsigned long int
    #define __xstrtol xstrtoul
    #define STRTOL_T_MINIMUM 0
    #define STRTOL_T_MAXIMUM ULONG_MAX
    #include "xstrtol.c"
    

    It's unusual (but not unheard-of) to include a .c file into another .c file.

    In C++, there are file naming conventions used for the similar situation where template definitions are defined in a .tcc file which is #included at the end of a .hpp header file.