Home > Enterprise >  How can sem_open() accept different argument sizes if function overloading isn't supported in C
How can sem_open() accept different argument sizes if function overloading isn't supported in C

Time:03-01

While learning about shared process semaphores, I noticed that sem_open() features two function prototypes: https://man7.org/linux/man-pages/man3/sem_open.3.html

sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

How is this possible if function overloading isn't supported by C?

CodePudding user response:

C does not have overloading. What is does have is variadic functions.

Overloaded functions are functions that have multiple forms of the function with different arguments for each one.

Variadic functions are functions in C that can take a variable number of arguments. This is indicated with an ellipses (...), and while this is not apparent in the man page, if you look at the source code for sem_open() you can see it:

/* Open a named semaphore NAME with open flags OFLAG.  */
extern sem_t *sem_open (const char *__name, int __oflag, ...) __THROW;

As you can see, after __name and __oflag, the ellipses indicates that technically any number of arguments can be entered. But what the man page indicates is what variables sem_open() can actually handle. So really, this isn't two functions with different logic, but a single function that can handle two different sets of arguments.

If you'd like to know more, there is this interesting article that covers some of the history behind variadic functions.

CodePudding user response:

The key is found in the manpage (which you linked):

If O_CREAT is specified in oflag, then two additional arguments must be supplied.

That's exactly the way variadic functions work in C. A variadic function has a fixed number of parameters, each with a well-defined type, and then a ..., which can be any number of arguments of any type, with the proviso that the called function has to be able to figure out the type of each argument in order to reference it. printf is indeed the clearest example: the format string includes enough information for printf to know exactly how many and what type of arguments to expect.

Note that guessing is not permitted. If the function asks for an argument which wasn't provided or asks for a different type than the provided argument, it doesn't get a friendly error indication or a second chance. The result is Undefined Behaviour: anything can happen, including abrupt termination or a nonsensical result. Or a result which seems to make sense but has no basis in reality.

Like open, sem_open uses this to allow arguments which are only needed in certain well-defined circumstances. If it is possible that the call will create a new semaphore (or file, in the case of open), it will request the additional arguments, assuming that they are of the types specified in the documentation.

The caller is responsible for ensuring that the call is correct. Note that since variadic arguments do not have a declared type, the compiler cannot insert type conversions. So if the function is expecting a double, it cannot be called with an int, which would normally be possible. Also, if a variadic argument is supposed to be void*, it must be void*, and not, for example, 0 (or NULL), because the automatic conversion from 0 to a null pointer can't be done.

However, the caller is allowed to provide too many arguments, or conversely the called function is not required to examine every argument supplied. (It can't skip over arguments, but it doesn't need to get to the end of the list.)

In retrospect, this may seem like a terrible language feature. But it seemed like a good idea at the time, and it's not going away now.

  • Related