A.2.2.3 How Many Arguments Were Supplied

There is no general way for a function to determine the number and type
of the optional arguments it was called with. So whoever designs the
function typically designs a convention for the caller to specify the number
and type of arguments. It is up to you to define an appropriate calling
convention for each variadic function, and write all calls accordingly.

One kind of calling convention is to pass the number of optional
arguments as one of the fixed arguments. This convention works provided
all of the optional arguments are of the same type.

A similar alternative is to have one of the required arguments be a bit
mask, with a bit for each possible purpose for which an optional
argument might be supplied. You would test the bits in a predefined
sequence; if the bit is set, fetch the value of the next argument,
otherwise use a default value.

A required argument can be used as a pattern to specify both the number
and types of the optional arguments. The format string argument to
printf is one example of this (see Formatted Output Functions).

Another possibility is to pass an “end marker” value as the last
optional argument. For example, for a function that manipulates an
arbitrary number of pointer arguments, a null pointer might indicate the
end of the argument list. (This assumes that a null pointer isn’t
otherwise meaningful to the function.) The execl function works
in just this way; see Executing a File.