Search notes:

Preprocessor: __VA_ARGS__ : count arguments

This is an attempt to define a few variadic macros that can be used to count the number of arguments given.

ELEVENTH_ARGUMENT

First, a simple macro is defined that just evaluates to the 11th argument.
#define ELEVENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, ...) a11
Github repository about-preprocessor, path: /macros/__VA_ARGS__/count-arguments/eleventh-argument.h
The following program uses this macro to test it.
#include "eleventh-argument.h"
#include <stdio.h>

int main() {
  printf("The 11th argument is: %s\n",
      ELEVENTH_ARGUMENT("one", "two", 3, 4, five, "six", 7, '8', "9", ten, "eleven", twelve, 13, "14"));
}
Github repository about-preprocessor, path: /macros/__VA_ARGS__/count-arguments/eleventh-argument.c
When run, it prints
The 11th argument is: eleven

COUNT_ARGUMENTS

The next macro (COUNT_ARGUMENTS) builds upon ELEVENTH_ARGUMENT. The more arguments that are passed to COUNT_ARGUMENTS, the more the »counting arguments« (9, 8, 7…) are pushed to the right. Thus the macro evaluates to the number of arguments that are passed to the macro.
#include "eleventh-argument.h"

// Note: With GCC, the preprocessor eliminates the comma in
//   , ## __VA_ARGS__
// IF __VA_ARGS__ is empty. (https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html)
// This is necessary to correctly count the arguments
//
#define COUNT_ARGUMENTS(...) ELEVENTH_ARGUMENT(dummy, ## __VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
Github repository about-preprocessor, path: /macros/__VA_ARGS__/count-arguments/count-arguments.h
The behaviour of the macro can be tested with the following test program:
#include <stdio.h>
#include "count-arguments.h"


int main() {

  printf("              has %d arguments\n"    , COUNT_ARGUMENTS());
  printf("one           has %d arguments\n"    , COUNT_ARGUMENTS(one));
  printf("1, 2, 3, 4, 5 has %d arguments\n"    , COUNT_ARGUMENTS(1, 2, 3, 4, 5));
  printf("foo, bar, baz has %d arguments\n"    , COUNT_ARGUMENTS(foo, bar, baz));
  printf("\"xyz\",\"abcde\" has %d arguments\n", COUNT_ARGUMENTS("xyz", "abcde"));


}
Github repository about-preprocessor, path: /macros/__VA_ARGS__/count-arguments/count-arguments.c
It prints:
              has 0 arguments
one           has 1 arguments
1, 2, 3, 4, 5 has 5 arguments
foo, bar, baz has 3 arguments
"xyz","abcde" has 2 arguments

PRINT_COUNT_ARGUMENTS

The next program is more or less the same as the last one. However, it encapsulates the printf in its own macro:
#include <stdio.h>
#include "count-arguments.h"

#define PRINT_COUNT_OF_ARGUMENTS(...) printf("%-40s has %d arguments\n", #__VA_ARGS__, COUNT_ARGUMENTS(__VA_ARGS__));

int main() {


  PRINT_COUNT_OF_ARGUMENTS(1, 2, 3, 4);
  PRINT_COUNT_OF_ARGUMENTS("foo", "bar", "baz");
  PRINT_COUNT_OF_ARGUMENTS(x, y, z, "tq84", hello, world, 'etc');

}
Github repository about-preprocessor, path: /macros/__VA_ARGS__/count-arguments/print-count-arguments.c

DEBUG_VARIABLE_ARGUMENTS

debug-variable-arguments.h is a file to be included. It concatenates DEBUG_ with the result of COUNT_ARGUMENTS to produce something like DEBUG_2 which takes a printf-format and two arguments.
#include "count-arguments.h"
#include <stdio.h>

#define CONCAT(a, b) a ## b
#define CONCAT2(a, b) CONCAT(a, b)

#define DEBUG_VARIABLE_ARGUMENTS(FORMAT, ...) CONCAT2(DEBUG_, COUNT_ARGUMENTS(__VA_ARGS__))(FORMAT, ##__VA_ARGS__)

#define DEBUG_0(FORMAT)                   printf(FORMAT)
#define DEBUG_1(FORMAT, ARG1)             printf(FORMAT, ARG1)
#define DEBUG_2(FORMAT, ARG1, ARG2)       printf(FORMAT, ARG1, ARG2)
#define DEBUG_3(FORMAT, ARG1, ARG2, ARG3) printf(FORMAT, ARG1, ARG2, ARG3)
Github repository about-preprocessor, path: /macros/__VA_ARGS__/count-arguments/debug-variable-arguments.h
Thus, the macro DEBUG_VARIABLE_ARGUMENTS can be used to call printf via a macro and a varying number of arguments:
#include "debug-variable-arguments.h"

int main() {

  DEBUG_VARIABLE_ARGUMENTS("hello, world\n");
  DEBUG_VARIABLE_ARGUMENTS("The number is: %d\n", 42);
  DEBUG_VARIABLE_ARGUMENTS("%d %s\n", 99, "Bottles");
  DEBUG_VARIABLE_ARGUMENTS("%s - %s - %s", "foo", "bar", "baz");
}
Github repository about-preprocessor, path: /macros/__VA_ARGS__/count-arguments/debug-variable-arguments.c

Makefile

The makefile to create the test programs:
all: eleventh-argument count-arguments print-count-arguments debug-variable-arguments

eleventh-argument: eleventh-argument.c eleventh-argument.h
	gcc eleventh-argument.c -o eleventh-argument

count-arguments: count-arguments.c count-arguments.h eleventh-argument.h
	gcc count-arguments.c -o count-arguments

print-count-arguments: print-count-arguments.c count-arguments.h eleventh-argument.h
	gcc print-count-arguments.c -o print-count-arguments

debug-variable-arguments: debug-variable-arguments.c debug-variable-arguments.h count-arguments.h eleventh-argument.h
	gcc debug-variable-arguments.c -o debug-variable-arguments
Github repository about-preprocessor, path: /macros/__VA_ARGS__/count-arguments/Makefile

See also

Preprocessor: __VA_ARGS__ (Variadic macros)

Index