Varargs in c and Objective-C
Variadic arguments in c, and how to use them in Objective-C
With varargs, as their name suggests (var-args), you can define a function or method that takes a variable number of arguments. This was most commonly used in Objective-C with
initWithObjectsAndKeys initializer methods prior to the introduction of array and dictionary literals. While no longer as popular, it is still a useful tool particularly when the use of a literal is not the best option.
Use in c
Your favourite function in c may be a variadic one, certainly if that function is
printf() or one its siblings like
snprintf(). They are some of the most commonly used functions in the standard c library.
To use varargs yourself, first you must include
Note: the older
varargs.h is deprecated. Do not use it unless you must.
Defining a variadic function can be super simple, but can make the implementation difficult if not impossible. In this example, how are you going to determine how many arguments have been provided?
It is almost always beneficial to include a
count, or some way to indicate how many additional arguments you are providing.
Sometimes its also beneficial to manually include the first argument particularly when you want to ensure at least one argument is given or hint to a user what type is expected.
The implementation should roughly follow this pattern.
An example of averaging
doubles could look as follows.
Note: The first argument is used in the definition of sum. The loop will never see the first argument as it starts on the argument after the first argument.
Use in Objective-C
As in c, you must include
stdarg.h. Though as this is Objective-C you should use
Objective-C is a much more dynamic language than c and as a result it is common to find the use of nil terminated varargs lists. A naive approach to an interface would look something like this.
This creates room for mistakes. What if you forget to terminate the arguments with a nil? You could loop forever! More realistically, it would loop until you found a random nil on the stack. Fortunately GGC and Clang provide an
__attribute__ to add compile-time detection of the missing
nil. They call it a
The Foundation framework goes another step further and conveniently wraps the sentinel attribute with the macro
NS_REQUIRES_NIL_TERMINATION. An Example of its use would be
initWithObjects which is defined as follows.
If you are using the
nil terminated approach you should always include it in your
There is none. The compiler will not raise any compile-time errors for the use of a wrong type. The compiler doesn’t know what type you are expecting.
This is not exactly true of
printf-like functions. There are additional
__attributes__ that some compilers support. Clang and GCC accept something like the following.
Note: In these examples ‘1’ is the index of the format argument, and the ‘2’ is the index of the first variadic argument.
On macOS there is a macro
__printflike(fmtarg, firstvararg) which makes this easier.
Chars, Shorts, and Floats
floats as the second argument of
va_arg() is not portable. C ‘promotes’
- ‘Variadic Function’ on Wikipedia
- stdarg documentation
- varargs documentation
Any source in this article is released under the ISC License.