How can I make a function with optional arguments in C?

19,941

Solution 1

The open function is declared as a variadic function. It will look something like this:

#include <stdarg.h>

int open(char const * filename, int flags, ...)
{
    va_list ap;
    va_start(ap, flags);

    if (flags & O_CREAT)
    {
        int mode = va_arg(ap, int);
        // ...
    }

    // ...

    va_end(ap);
}

The further arguments are not consumed unless you have indicated that they do in fact exist.

The same construction is used for printf.

The manual doesn't always make this explicit, since the only possible two signatures are (char const *, int) and (char const *, int, int), so there's little point in revealing that you the function actually accepts variable arguments. (You can test this by trying to compile something like open("", 1, 2, 3, 4, 5, 6).)

Solution 2

In all cases, a varargs function must be able to determine somehow, from the fixed arguments, how many variable arguments there are. For example, the printf() family of functions use the format string to determine the number and types of the arguments. The execl() function uses a sentinel (null pointer) to mark the end of the argument list. It would be possible to use a count instead of a sentinel (but if you're going to do that, the chances are that a count and an array in a non-varargs function would work as well as, if not better than, a count and a list of arguments). The open() function uses one of the flag bits to determine whether the mode should be present — see Kerrek SB's answer.

The main() function is a special case. The implementation (compiler) is prohibited from declaring a prototype for it, and must accept at least the two forms:

int main(int argc, char **argv);
int main(void);

or their equivalents. It may accept other forms too; see What's the use of the third environment variable in the C main()? for one common form. In C, but not C++, a standard compiler can document other return types — and Microsoft has documented void as a valid return type from VS 2008 onwards.

Because there is no implementation-provided prototype for main(), the compiler can't officially reject any declarations/definitions of main(), though it might pass comment on forms it doesn't recognize (GCC does comment on main() functions that do not return an int type, for example).

Share:
19,941

Related videos on Youtube

gangadhars
Author by

gangadhars

A developer

Updated on September 15, 2022

Comments

  • gangadhars
    gangadhars over 1 year

    Recently I got a question when writing a program for file opening.

    Let me explain my question clearly. Here I'm taking open call as an example.

    To create a file:

    open("file_name", O_CREAT, 0766); //passing 3 parametrs
    

    To open a file:

    open("file_name", O_RDWR); //only 2 arguments.
    

    Then I clearly observed this point and it also works for main() too.

    main(void) //worked
    main(int argc, char **argv); //worked
    main(int argc) //worked and it's doesn't give an error like "too few arguments". 
    main() //worked 
    

    So how we can create these optional arguments? How exactly can the compiler validate these prototypes? If possible, please write an example program.

  • gangadhars
    gangadhars over 10 years
    but how can they validate these. its not giving any argument like "too few arguments".
  • Kerrek SB
    Kerrek SB over 10 years
    @SGG: The same way that printf can validate whether you've passed the correct number and type of arguments.
  • gangadhars
    gangadhars over 10 years
    @KerrekSB: sorry, i'm missing clarity. See there is a function which takes one argument or nothing(void). I mean, function should be validate if i call function() or function(10). Can you write the definition for that function.
  • Kerrek SB
    Kerrek SB over 10 years
    @SGG: You cannot. You have to document your contract and rely on the user sticking to the contract. For that matter, you cannot have zero arguments, you must have at least one for varargs-style functions.
  • Jonathan Leffler
    Jonathan Leffler over 10 years
    Comment: you could move all the va_list code inside the condition; it is only needed there. You don't have to use va_start() in a varargs function, even though you must use it before you can access any of the variable arguments (and when you do use it, you must call va_end() too).
  • Jonathan Leffler
    Jonathan Leffler over 10 years
    Hmmm...the standard uses the name oflags for what you called mode, and the third argument is a mode_t argument for the 'mode' (permissions) on the file. Just an FYI.
  • Keith Thompson
    Keith Thompson over 10 years
    The open function predates the , ... syntax that was introduced by the 1989 ANSI C standard. Early versions of open simply documented the two different forms, and depend on weak type checking to permit both of them (in the absence of prototypes, the compiler won't diagnose calls with the wrong number of arguments, and prototypes weren't introduced until 1989). With the introduction of the ANSI C standard, the definition of open was updated to use , ... (and presumably to use <stdarg.h> internally).
  • Keith Thompson
    Keith Thompson over 10 years
    Actually a compiler can reject forms of main that it doesn't accept. Alternate forms are implementation-defined, meaning that the compiler must be accompanied by a document that lists them. A program with a definition that's neither one of the two standard forms nor an implementation-defined form for the current compiler has undefined behavior (by omission, since the standard doesn't define the behavior) (5.1.2.2.1). Rejecting a translation unit is an acceptable response to undefined behavior (3.4.3).