-
-
Save royratcliffe/6d8f58b0f518a56fa55974f030f7dfdc to your computer and use it in GitHub Desktop.
va-nargs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * SPDX-License-Identifier: MIT | |
| * SPDX-FileCopyrightText: 2026, Roy Ratcliffe, Northumberland, United Kingdom | |
| */ | |
| /*! | |
| * \file va.h | |
| * \brief Header file for variadic argument counting macros. | |
| * \details This file contains macros for counting the number of variadic | |
| * arguments passed to a macro. It can count up to 63 arguments and returns the | |
| * count as a compile-time constant. If there are no arguments, it returns 0. If | |
| * there are more than 63 arguments, it returns 63. | |
| */ | |
| #ifndef VA_H | |
| #define VA_H | |
| /*! | |
| * \brief Count number of variadic arguments. | |
| * \details This macro can count up to 63 arguments. If the number of arguments | |
| * is more than 63, it will return 63. | |
| * \param ... Variadic arguments. | |
| * \return Number of variadic arguments. | |
| * \note If there are no arguments, returns 0. Achieved by using ##__VA_ARGS__ | |
| * which removes the comma if there are no arguments. | |
| * \note The use of ##__VA_ARGS__ is not supported by all compilers, such as | |
| * CCRX. For compilers that do not support ##__VA_ARGS__, the macro is defined | |
| * without it, which may lead to incorrect counting when no arguments are | |
| * provided. | |
| * \note The maximum number of arguments that can be counted is 63 due to the | |
| * use of reverse sequential numbers from 62 to 0 as padding. If more than 63 | |
| * arguments are provided, the count will be capped at 63. | |
| * \note Why the initial argument is _0: The pasting operator \c ## concatenates | |
| * the initial argument _0 with the variadic arguments. This ensures that when | |
| * there are no variadic arguments, the macro still expands correctly and | |
| * returns 0. If there were no initial argument, the macro would not expand | |
| * correctly when no arguments are provided, leading to a compilation error. | |
| */ | |
| #if !defined(__CCRX__) | |
| #define VA_NARGS(...) _VA_NARGS(_0, ##__VA_ARGS__, _VA_RSEQ63()) | |
| #else | |
| #define VA_NARGS(...) _VA_NARGS(_0, __VA_ARGS__, _VA_RSEQ63()) | |
| #endif | |
| /*! | |
| * \brief Expands variadic arguments and selects the 64th. | |
| * \param ... Variadic arguments padded with reverse sequential numbers. | |
| * \return Number of variadic arguments. | |
| */ | |
| #define _VA_NARGS(...) _VA_ARG64(__VA_ARGS__) | |
| /*! | |
| * \brief Answers the 64th argument. | |
| * \details The 64th argument is determined by the position of the arguments. | |
| * Achieved by using reverse sequential numbers from 62 to 0 as padding. The | |
| * 64th position will correspond to the number of arguments. | |
| * \param ... Variadic arguments padded with reverse sequential numbers. | |
| * \return The 64th argument from the variadic arguments. | |
| */ | |
| #define _VA_ARG64(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ | |
| _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, \ | |
| _59, _60, _61, _62, _63, _64, ...) \ | |
| _64 | |
| /*! | |
| * \brief Reverse sequential numbers from 62 to 0. | |
| * \details Used to add padding to the variadic arguments so that the 64th | |
| * position corresponds to the number of arguments. | |
| */ | |
| #define _VA_RSEQ63() \ | |
| 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, \ | |
| 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 | |
| #endif /* VA_H */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <va.h> | |
| #include <assert.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <unistd.h> | |
| void test_VA_NARGS(void) { | |
| assert(0 == VA_NARGS()); | |
| assert(1 == VA_NARGS(1)); | |
| assert(2 == VA_NARGS(1, 2)); | |
| assert(3 == VA_NARGS(1, 2, 3)); | |
| assert(4 == VA_NARGS(1, 2, 3, 4)); | |
| assert(5 == VA_NARGS(1, 2, 3, 4, 5)); | |
| assert(6 == VA_NARGS(1, 2, 3, 4, 5, 6)); | |
| assert(7 == VA_NARGS(1, 2, 3, 4, 5, 6, 7)); | |
| assert(8 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8)); | |
| assert(9 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9)); | |
| assert(10 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); | |
| assert(11 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); | |
| assert(12 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); | |
| assert(13 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)); | |
| assert(14 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)); | |
| assert(15 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); | |
| assert(16 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); | |
| assert(17 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17)); | |
| assert(18 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)); | |
| assert(19 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)); | |
| assert(20 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)); | |
| assert(21 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)); | |
| assert(22 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22)); | |
| assert(23 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23)); | |
| assert(24 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24)); | |
| assert(25 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25)); | |
| assert(26 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)); | |
| assert(27 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27)); | |
| assert(28 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28)); | |
| assert(29 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29)); | |
| assert(30 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30)); | |
| assert(31 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31)); | |
| assert(32 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)); | |
| assert(62 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, /* 1..10 */ | |
| 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, /* 11..20 */ | |
| 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, /* 21..30 */ | |
| 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 31..40 */ | |
| 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, /* 41..50 */ | |
| 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, /* 51..60 */ | |
| 61, 62)); | |
| assert(63 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, /* 1..10 */ | |
| 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, /* 11..20 */ | |
| 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, /* 21..30 */ | |
| 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 31..40 */ | |
| 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, /* 41..50 */ | |
| 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, /* 51..60 */ | |
| 61, 62, 63)); | |
| assert(63 == VA_NARGS(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, /* 1..10 */ | |
| 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, /* 11..20 */ | |
| 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, /* 21..30 */ | |
| 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 31..40 */ | |
| 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, /* 41..50 */ | |
| 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, /* 51..60 */ | |
| 61, 62, 63, 64)); | |
| } | |
| int main(void) { | |
| (void)printf("Hello, World from %s!!!\n", "va_test"); | |
| test_VA_NARGS(); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment