Tracking User-Defined `struct` Members with a Designated Initializer Syntax - unit-testing

For a unit-testing library that I'm writing, rexo, I would like to implement an automatic test registration mechanism compatible with both C99 and C++11.
Automatic test registration usually goes along the lines of:
providing macros for the users to define test suites and test cases.
having the macros instantiate file-level structures that contain the data needed to fully describe their respective test suites/cases.
having some logic that can somehow discover these structure instances at run-time.
I've got most of this sorted out but one bit: providing a nice interface for defining additional data to be attached to each test suite/case.
The (non-public) data structure to attach looks like this:
struct rx__data {
const char *name;
int value;
rx_run_fn run;
};
I managed to get a RX__MAKE_DATA() macro working with a designated initializer syntax, as follows:
/* https://github.com/swansontec/map-macro ----------------------------------- */
#define EVAL0(...) __VA_ARGS__
#define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__)))
#define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL4(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define MAP_END(...)
#define MAP_OUT
#define MAP_GET_END2() 0, MAP_END
#define MAP_GET_END1(...) MAP_GET_END2
#define MAP_GET_END(...) MAP_GET_END1
#define MAP_NEXT0(test, next, ...) next MAP_OUT
#define MAP_NEXT1(test, next) MAP_NEXT0(test, next, 0)
#define MAP_NEXT(test, next) MAP_NEXT1(MAP_GET_END test, next)
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP1)(f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP0)(f, peek, __VA_ARGS__)
#define MAP(f, ...) EVAL(MAP1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
/* -------------------------------------------------------------------------- */
typedef int (*rx_run_fn)();
struct rx__data {
const char *name;
int value;
rx_run_fn run;
};
int run() { return 999; }
#ifdef __cplusplus
#define RX__WRAP_ASSIGNMENT(x) out x;
#define RX__MAKE_DATA(...) \
[]() -> struct rx__data { \
struct rx__data out = {}; \
MAP(RX__WRAP_ASSIGNMENT, __VA_ARGS__); \
return out; \
}()
#else
#define RX__MAKE_DATA(...) { __VA_ARGS__ }
#endif
static const struct rx__data foo
= RX__MAKE_DATA(.name = "abc", .value = 123, .run = run);
It's all good except that, since the rx__data struct can be attached to both test suites and test cases, I'd like to have a mechanism that allows me to know if a data member has been explicitely set or not by the user. This way, I can infer the final data to apply to a test case by:
retrieving the data to inherit from the parent test suite.
overriding only the members from the test suite that were explicitely set onto the test case.
For example
RX_TEST_SUITE(my_suite, .name = "abc", .value = 123, .run = run);
RX_TEST_CASE(my_suite, my_case, .value = 666)
{
...
}
would result in ‘my_case’ having the data {.name = "abc", .value = 666, .run = run} attached to it.
For this to work, I thought of adding a boolean value for each field, to keep track of what has been explicitely defined or not by the user:
typedef int (*rx_run_fn)();
struct rx__data {
const char *name;
int value;
rx_run_fn run;
int name_defined;
int value_defined;
int run_defined;
};
int run() { return 999; }
#ifdef __cplusplus
#define RX__ARG(field, value) out.field = value; out.field##_defined = 1
#define RX__MAKE_DATA(...) \
[]() -> struct rx__data { \
struct rx__data out = {}; \
__VA_ARGS__; \
return out; \
}();
#else
#define RX__ARG(field, value) .field = value, .field##_defined = 1
#define RX__MAKE_DATA(...) { __VA_ARGS__ }
#endif
#define RX_NAME_ARG(x) RX__ARG(name, x)
#define RX_VALUE_ARG(x) RX__ARG(value, x)
#define RX_RUN_ARG(x) RX__ARG(run, x)
static const struct rx__data foo
= RX__MAKE_DATA(RX_NAME_ARG("abc"), RX_VALUE_ARG(123), RX_RUN_ARG(run));
And it's all working great here again, except that the user now has to set the arguments using macros instead of the previous designated initializer syntax.
So the questions is: how can I keep track of these user-defined struct members while preserving the designated initializer syntax?
Note: if possible, I'd really like to have a robust way of detecting if a member was defined, so no in-band indicators—that is, no ”if this member has this magic value, then it's likely that is wasn't explicitely set”.

Just found my own answer, thanks rubber duck!
#include <stdio.h>
/* -------------------------------------------------------------------------- */
#define EXPAND(x) x
#define ARG_IDX(_1, _2, _3, _4, _5, _6, _7, _8, n, ...) n
#define COUNT_ARGS(...) EXPAND(ARG_IDX(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define CONCAT_0(a, b) a ## b
#define CONCAT(a, b) CONCAT_0(a, b)
#define APPLY_0(x)
#define APPLY_1(x, _1) \
x(_1)
#define APPLY_2(x, _1, _2) \
x(_1) x(_2)
#define APPLY_3(x, _1, _2, _3) \
x(_1) x(_2) x(_3)
#define APPLY_4(x, _1, _2, _3, _4) \
x(_1) x(_2) x(_3) x(_4)
#define APPLY_5(x, _1, _2, _3, _4, _5) \
x(_1) x(_2) x(_3) x(_4) x(_5)
#define APPLY_6(x, _1, _2, _3, _4, _5, _6) \
x(_1) x(_2) x(_3) x(_4) x(_5) x(_6)
#define APPLY_7(x, _1, _2, _3, _4, _5, _6, _7) \
x(_1) x(_2) x(_3) x(_4) x(_5) x(_6) x(_7)
#define APPLY_8(x, _1, _2, _3, _4, _5, _6, _7, _8) \
x(_1) x(_2) x(_3) x(_4) x(_5) x(_6) x(_7) x(_8)
#define APPLY(x, ...) EXPAND(x(__VA_ARGS__))
#define MAP(x, ...) \
EXPAND(APPLY(CONCAT(APPLY_, COUNT_ARGS(__VA_ARGS__)), x, __VA_ARGS__))
/* -------------------------------------------------------------------------- */
typedef int (*rx_run_fn)();
int run() { return 999; }
#ifdef __cplusplus
struct rx__data {
struct {
const char *name;
double number;
rx_run_fn run;
} value;
struct {
int name;
int number;
int run;
} defined;
};
#define RX__WRAP_ASSIGNMENT(x) out.value x; out.defined x ? 1 : 1;
#define RX__MAKE_DATA(...) \
[]() -> struct rx__data { \
struct rx__data out = {}; \
MAP(RX__WRAP_ASSIGNMENT, __VA_ARGS__); \
return out; \
}()
#define RX__GET_ARG_VALUE(data, field) data . value . field
#define RX__IS_ARG_DEFINED(data, field) data . defined . field
#else
struct rx__data {
const char *name;
int name_defined;
double number;
int number_defined;
rx_run_fn run;
int run_defined;
};
#define RX__WRAP_ASSIGNMENT(x) x, 1,
#define RX__MAKE_DATA(...) { MAP(RX__WRAP_ASSIGNMENT, __VA_ARGS__) }
#define RX__GET_ARG_VALUE(data, field) data . field
#define RX__IS_ARG_DEFINED(data, field) data . field##_defined
#endif
static const struct rx__data foo = RX__MAKE_DATA(
.name = "abc", .number = 1.23, .run = run);
int
main(void)
{
if (RX__IS_ARG_DEFINED(foo, name)) {
printf("name : %s\n", RX__GET_ARG_VALUE(foo, name));
} else {
printf("name : (not defined)\n");
}
if (RX__IS_ARG_DEFINED(foo, number)) {
printf("number : %f\n", RX__GET_ARG_VALUE(foo, number));
} else {
printf("number : (not defined)\n");
}
if (RX__IS_ARG_DEFINED(foo, run)) {
printf("run : %d\n", RX__GET_ARG_VALUE(foo, run)());
} else {
printf("run : (not defined)\n");
}
return 0;
}

Related

Error in macro with __VA_OPT__ and parenthesis

I am using c++,gcc. I have code for logging with macro like this:
#define E_DEBUG(level, ...) \
if (err_get_debug_level() >= level) \
err_msg(ERR_DEBUG, FILELINE, __VA_OPT__)
#define ERR_DEBUG 1
#define FILELINE __FILE__ , __LINE__
int err_get_debug_level(void);
void err_msg(int lvl, const char *path, long ln, const char *fmt, ...);
int main ( void ) {
E_DEBUG(1,("%d",14));
}
The code give an error VA_OPT must be followed by an open parenthesis
I change the code according this Error in macro with __va_args__ and parenthesis.
The code look like:
#define PASTE(...) __VA_OPT__
#define E_DEBUG(level, ...) \
if (err_get_debug_level() >= level) \
err_msg(ERR_DEBUG, FILELINE, PASTE __VA_OPT__)
#define ERR_DEBUG 1
#define FILELINE __FILE__ , __LINE__
int err_get_debug_level(void);
void err_msg(int lvl, const char *path, long ln, const char *fmt, ...);
int main ( void ) {
E_DEBUG(1,("%d",14));
}
It gives an error unterminated VA_OPT. How should I fix it?
__VA_OPT__ is used to conditionally insert something in your macro, it's not equivalent to __VA_ARGS__, you need both:
#define E_DEBUG(level, ...) \
if (err_get_debug_level() >= level) \
err_msg(ERR_DEBUG, FILELINE __VA_OPT__(,) __VA_ARGS__)
This will not compile with your code because you used ("%d", 14) and I don't really understand why. If you remove the extra brackets, the code compiles.

Export bitfield to an array

I've declared this bit field. What I am trying to do is to get the whole value of the bitfield in binary and convert it into an array so I can use the index and address every '1' value.
union{
struct shape{
uint8_t p0 : 1;
uint8_t p1 : 1;
uint8_t p2 : 1;
uint8_t p3 : 1;
uint8_t p4 : 1;
uint8_t p5 : 1;
uint8_t p6 : 1;
uint8_t p7 : 1;
};
uint8_t row;
}rows[8*2+4];
what I am trying to do is to export the bitfield to have it an array like uint8_t tab[8] = {0,1,1,0,0,1,0,1};
Is that even possible? Any tips?
Thanks in advance
If you are, in fact, starting from a uint8_t, then you don't need or want to fiddle about with bit-fields...
...assuming (a) Little-Endian and (b) that you can write an unaligned uint64_t:
void explode_byte(uint8_t r[8], uint8_t b)
{
uint64_t x ;
x = b ;
x |= x << (32 - 4) ;
x |= x << (16 - 2) ;
x |= x << ( 8 - 1) ;
*(uint64_t*)r = x & (uint64_t)0x0101010101010101 ;
}
See "Hacker's Delight" by Henry S. Warren :-)
But, if you are starting with the bit-fields, then you have a quite different problem: you really cannot make any assumptions about how bit fields are stored -- all you can do is read/write individual fields. So you have no choice but to copy each bit-field to its respective byte... as given in other answers.
Instead of using bit fields, use just an array of uint8_t and access each bit using shifts and masks. There is actually no other way to access bits by index in standard C (not counting any library implementations).
uint8_t data[SIZE];
...
data[bitIndex >> 3] |= 1 << (bitIndex & 7); // set bit at bitIndex
data[bitIndex >> 3] &= ~(1 << (bitIndex & 7); // clear bit at bitIndex
bitValue = !!(data[bitIndex >> 3] & (1 << bitIndex & 7)); // read bit at bitIndex
Using larger types (16, 32, 64) can be more efficient but requires suitably changed shifts and masks (eg, 4 and 15 for uint16_t).
If you want to just export your bitfields, it is possible with user-defined conversion from your union to std::array. Note that, it is just possible to read bits( not set ).
union{
struct shape{
uint8_t p0 : 1;
uint8_t p1 : 1;
uint8_t p2 : 1;
uint8_t p3 : 1;
uint8_t p4 : 1;
uint8_t p5 : 1;
uint8_t p6 : 1;
uint8_t p7 : 1;
} bits;
operator std::array<bool , 8>(){
std::array<bool , 8> exported_array;
exported_array[ 0 ] = bits.p0;
exported_array[ 1 ] = bits.p1;
exported_array[ 2 ] = bits.p2;
exported_array[ 3 ] = bits.p3;
exported_array[ 4 ] = bits.p4;
exported_array[ 5 ] = bits.p5;
exported_array[ 6 ] = bits.p6;
exported_array[ 7 ] = bits.p7;
return exported_array;
}
uint8_t row;
} rows[8*2+4];
int main()
{
rows[0].row = static_cast<uint8_t>( 643211 );
std::array< bool , 8 > data = rows[ 0 ];
for ( auto bit : data )
std::cout << static_cast<int>( bit );
}
But I don't suggest to use this method. As far as i understand, you read a value from somewhere and you want to access/manipulate the bits like an array. std::bitset is a good option to do that.
Possible implementation like this :
#include <cstdint>
#include <iostream>
#include <bitset>
int main()
{
uint8_t data_comes_from_somewhere = 0b01001001;
std::string data_comes_from_somewhere_as_string { "11101001" };
std::bitset<8> bitfields { data_comes_from_somewhere };
std::bitset<8> bitfields_2 { data_comes_from_somewhere_as_string };
std::cout << bitfields << std::endl;
std::cout << bitfields_2 << std::endl;
// Set leftmost bit
bitfields[ 7 ] = 1;
int leftmost_bit = bitfields[ 7 ];
std::cout << bitfields << std::endl;
std::cout << leftmost_bit << std::endl;
}
rows[8] = (union row){.p0 = 0,.p1 = 1,.p2 = 1,.p3 = 0,.p4 = 0,.p5= 1,.p6 = 0,.p7 = 1};
or
rows[8].row = {b01100101}; if you define all the bin balues yourself like below or not portable rows[8].row = {0b01100101};
#ifndef __BIN_8BITS__
#define __BIN_8BITS__
#define b00000000 0x0000
#define b00000001 0x0001
#define b00000010 0x0002
#define b00000011 0x0003
#define b00000100 0x0004
#define b00000101 0x0005
#define b00000110 0x0006
#define b00000111 0x0007
#define b00001000 0x0008
#define b00001001 0x0009
#define b00001010 0x000A
#define b00001011 0x000B
#define b00001100 0x000C
#define b00001101 0x000D
#define b00001110 0x000E
#define b00001111 0x000F
#define b00010000 0x0010
#define b00010001 0x0011
#define b00010010 0x0012
#define b00010011 0x0013
#define b00010100 0x0014
#define b00010101 0x0015
#define b00010110 0x0016
#define b00010111 0x0017
#define b00011000 0x0018
#define b00011001 0x0019
#define b00011010 0x001A
#define b00011011 0x001B
#define b00011100 0x001C
#define b00011101 0x001D
#define b00011110 0x001E
#define b00011111 0x001F
#define b00100000 0x0020
#define b00100001 0x0021
#define b00100010 0x0022
#define b00100011 0x0023
#define b00100100 0x0024
#define b00100101 0x0025
#define b00100110 0x0026
#define b00100111 0x0027
#define b00101000 0x0028
#define b00101001 0x0029
#define b00101010 0x002A
#define b00101011 0x002B
#define b00101100 0x002C
#define b00101101 0x002D
#define b00101110 0x002E
#define b00101111 0x002F
#define b00110000 0x0030
#define b00110001 0x0031
#define b00110010 0x0032
#define b00110011 0x0033
#define b00110100 0x0034
#define b00110101 0x0035
#define b00110110 0x0036
#define b00110111 0x0037
#define b00111000 0x0038
#define b00111001 0x0039
#define b00111010 0x003A
#define b00111011 0x003B
#define b00111100 0x003C
#define b00111101 0x003D
#define b00111110 0x003E
#define b00111111 0x003F
#define b01000000 0x0040
#define b01000001 0x0041
#define b01000010 0x0042
#define b01000011 0x0043
#define b01000100 0x0044
#define b01000101 0x0045
#define b01000110 0x0046
#define b01000111 0x0047
#define b01001000 0x0048
#define b01001001 0x0049
#define b01001010 0x004A
#define b01001011 0x004B
#define b01001100 0x004C
#define b01001101 0x004D
#define b01001110 0x004E
#define b01001111 0x004F
#define b01010000 0x0050
#define b01010001 0x0051
#define b01010010 0x0052
#define b01010011 0x0053
#define b01010100 0x0054
#define b01010101 0x0055
#define b01010110 0x0056
#define b01010111 0x0057
#define b01011000 0x0058
#define b01011001 0x0059
#define b01011010 0x005A
#define b01011011 0x005B
#define b01011100 0x005C
#define b01011101 0x005D
#define b01011110 0x005E
#define b01011111 0x005F
#define b01100000 0x0060
#define b01100001 0x0061
#define b01100010 0x0062
#define b01100011 0x0063
#define b01100100 0x0064
#define b01100101 0x0065
#define b01100110 0x0066
#define b01100111 0x0067
#define b01101000 0x0068
#define b01101001 0x0069
#define b01101010 0x006A
#define b01101011 0x006B
#define b01101100 0x006C
#define b01101101 0x006D
#define b01101110 0x006E
#define b01101111 0x006F
#define b01110000 0x0070
#define b01110001 0x0071
#define b01110010 0x0072
#define b01110011 0x0073
#define b01110100 0x0074
#define b01110101 0x0075
#define b01110110 0x0076
#define b01110111 0x0077
#define b01111000 0x0078
#define b01111001 0x0079
#define b01111010 0x007A
#define b01111011 0x007B
#define b01111100 0x007C
#define b01111101 0x007D
#define b01111110 0x007E
#define b01111111 0x007F
#define b10000000 0x0080
#define b10000001 0x0081
#define b10000010 0x0082
#define b10000011 0x0083
#define b10000100 0x0084
#define b10000101 0x0085
#define b10000110 0x0086
#define b10000111 0x0087
#define b10001000 0x0088
#define b10001001 0x0089
#define b10001010 0x008A
#define b10001011 0x008B
#define b10001100 0x008C
#define b10001101 0x008D
#define b10001110 0x008E
#define b10001111 0x008F
#define b10010000 0x0090
#define b10010001 0x0091
#define b10010010 0x0092
#define b10010011 0x0093
#define b10010100 0x0094
#define b10010101 0x0095
#define b10010110 0x0096
#define b10010111 0x0097
#define b10011000 0x0098
#define b10011001 0x0099
#define b10011010 0x009A
#define b10011011 0x009B
#define b10011100 0x009C
#define b10011101 0x009D
#define b10011110 0x009E
#define b10011111 0x009F
#define b10100000 0x00A0
#define b10100001 0x00A1
#define b10100010 0x00A2
#define b10100011 0x00A3
#define b10100100 0x00A4
#define b10100101 0x00A5
#define b10100110 0x00A6
#define b10100111 0x00A7
#define b10101000 0x00A8
#define b10101001 0x00A9
#define b10101010 0x00AA
#define b10101011 0x00AB
#define b10101100 0x00AC
#define b10101101 0x00AD
#define b10101110 0x00AE
#define b10101111 0x00AF
#define b10110000 0x00B0
#define b10110001 0x00B1
#define b10110010 0x00B2
#define b10110011 0x00B3
#define b10110100 0x00B4
#define b10110101 0x00B5
#define b10110110 0x00B6
#define b10110111 0x00B7
#define b10111000 0x00B8
#define b10111001 0x00B9
#define b10111010 0x00BA
#define b10111011 0x00BB
#define b10111100 0x00BC
#define b10111101 0x00BD
#define b10111110 0x00BE
#define b10111111 0x00BF
#define b11000000 0x00C0
#define b11000001 0x00C1
#define b11000010 0x00C2
#define b11000011 0x00C3
#define b11000100 0x00C4
#define b11000101 0x00C5
#define b11000110 0x00C6
#define b11000111 0x00C7
#define b11001000 0x00C8
#define b11001001 0x00C9
#define b11001010 0x00CA
#define b11001011 0x00CB
#define b11001100 0x00CC
#define b11001101 0x00CD
#define b11001110 0x00CE
#define b11001111 0x00CF
#define b11010000 0x00D0
#define b11010001 0x00D1
#define b11010010 0x00D2
#define b11010011 0x00D3
#define b11010100 0x00D4
#define b11010101 0x00D5
#define b11010110 0x00D6
#define b11010111 0x00D7
#define b11011000 0x00D8
#define b11011001 0x00D9
#define b11011010 0x00DA
#define b11011011 0x00DB
#define b11011100 0x00DC
#define b11011101 0x00DD
#define b11011110 0x00DE
#define b11011111 0x00DF
#define b11100000 0x00E0
#define b11100001 0x00E1
#define b11100010 0x00E2
#define b11100011 0x00E3
#define b11100100 0x00E4
#define b11100101 0x00E5
#define b11100110 0x00E6
#define b11100111 0x00E7
#define b11101000 0x00E8
#define b11101001 0x00E9
#define b11101010 0x00EA
#define b11101011 0x00EB
#define b11101100 0x00EC
#define b11101101 0x00ED
#define b11101110 0x00EE
#define b11101111 0x00EF
#define b11110000 0x00F0
#define b11110001 0x00F1
#define b11110010 0x00F2
#define b11110011 0x00F3
#define b11110100 0x00F4
#define b11110101 0x00F5
#define b11110110 0x00F6
#define b11110111 0x00F7
#define b11111000 0x00F8
#define b11111001 0x00F9
#define b11111010 0x00FA
#define b11111011 0x00FB
#define b11111100 0x00FC
#define b11111101 0x00FD
#define b11111110 0x00FE
#define b11111111 0x00FF
#endif

Variadic macros with zero or more additional arguments

I have a macro for checking results of some test methods:
#define Eval(func, ...) if (func == -1) { printf(__VA_ARGS__); return -1; }
I want to get this functionally:
Eval(Check_1(),"Check1 failed."); // case 1
Eval(Check_2()); // case 2
Eval(Check_3(), "some variable=%i", variableValue); // case 3
At case 1 I want to write comment to user ("Check1 failed") and then return -1 (it's work).
At case 2 I just want to return from method, not print any information for user. So I must to detect situation of empty comment and not to call printf() - it's not work.
If any of "Check_x" methods failed, i need exit from current method by return code -1;
Is it any way to do this with macro?
Very similar question was here: Standard alternative to GCC's ##VA_ARGS trick? , but I can't modify this code for my situation.
EDIT:
I use C99 standart.
At current version of my code case 2 compiled with error "expected an expression" (I think it because of comma and empty argument).
Also I need to use case 3 for print additional information (variable values).
So, second argument not actually simple string.
EDIT2:
I get solution for my task. Here I find it
// Macro to count of arguments
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 10,9,8,7,6,5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N
// Macro dispatcher
#define macro_dispatcher(func, ...) macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__))
#define macro_dispatcher_(func, nargs) macro_dispatcher__(func, nargs)
#define macro_dispatcher__(func, nargs) func ## nargs
#define EVAL_UNIVERSAL(...) macro_dispatcher(EV, __VA_ARGS__)(__VA_ARGS__)
#define EV1(func) if (func == -1) return -1;
#define EV2(func, ...) if (func == -1) { printf(__VA_ARGS__); return -1; }
#define EV3(func, ...) EV2(func, __VA_ARGS__)
#define EV4(func, ...) EV2(func, __VA_ARGS__)
#define EV5(func, ...) EV2(func, __VA_ARGS__)
#define EV6(func, ...) EV2(func, __VA_ARGS__)
#define EV7(func, ...) EV2(func, __VA_ARGS__)
And I use it like this:
EVAL_UNIVERSAL(CheckInitialParameters());
EVAL_UNIVERSAL(CheckInitialParameters(), "text");
EVAL_UNIVERSAL(CheckInitialParameters(), "%i", 1);
EVAL_UNIVERSAL(CheckInitialParameters(), "%i %i", 1, 2);
Very thanks to Jens Gustedt, and rmn (http://efesx.com/)
// Macro to count of arguments
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 10,9,8,7,6,5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N
// Macro dispatcher
#define macro_dispatcher(func, ...) macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__))
#define macro_dispatcher_(func, nargs) macro_dispatcher__(func, nargs)
#define macro_dispatcher__(func, nargs) func ## nargs
#define EVAL_UNIVERSAL(...) macro_dispatcher(EV, __VA_ARGS__)(__VA_ARGS__)
#define EV1(func) if (func == -1) return -1;
#define EV2(func, ...) if (func == -1) { printf(__VA_ARGS__); return -1; }
#define EV3(func, ...) EV2(func, __VA_ARGS__)
#define EV4(func, ...) EV2(func, __VA_ARGS__)
#define EV5(func, ...) EV2(func, __VA_ARGS__)
#define EV6(func, ...) EV2(func, __VA_ARGS__)
#define EV7(func, ...) EV2(func, __VA_ARGS__)
And I use it like this:
EVAL_UNIVERSAL(CheckInitialParameters());
EVAL_UNIVERSAL(CheckInitialParameters(), "text");
EVAL_UNIVERSAL(CheckInitialParameters(), "%i", 1);
EVAL_UNIVERSAL(CheckInitialParameters(), "%i %i", 1, 2);

How to define same macro function based on different parameters

#define UPUT_SET_CHECK_POINT1(appType, tag, argNum1, v1, ...) \
if(NUMARGS(##__VA_ARGS__) == 0) \
UPUT_SET_CHECK_POINTx(1, appType, tag, argNum1, v1, UPUT_P_INVALID, 0, UPUT_P_INVALID, 0, UPUT_P_INVALID, 0, UPUT_P_INVALID, 0, __FILE__, __LINE__, UPUT_SEQUENTIAL); \
else \
UPUT_SET_CHECK_POINTx(1, appType, tag, argNum1, v1, UPUT_P_INVALID, 0, UPUT_P_INVALID, 0, UPUT_P_INVALID, 0, UPUT_P_INVALID, 0, __FILE__, __LINE__ , __VA_ARGS__)
so when VA_ARGS is empty I am getting a compile time error "expected primary-expression before ')' token". Any way to fix the compilation error.
void UPUT_SET_CHECK_POINTx(int numArg, CtblAppType appType, int tag, UputArgPos argNum1, int v1, UputArgPos argNum2, int v2, UputArgPos argNum3, int v3, UputArgPos argNum4, int v4, UputArgPos argNum5, int v5, char* fileName, unsigned int lineNumber, UputCheckPointAlgo checkPointAlgo=UPUT_SEQUENTIAL);
If you are using GCC, you could use , ## __VA_ARGS__ to eliminate the comma when __VA_ARGS__ is empty.
#define UPUT_SET_CHECK_POINT1(appType, tag, argNum1, v1, ...) \
UPUT_SET_CHECK_POINTx(1, appType, tag, argNum1, v1, \
UPUT_P_INVALID, 0, \
UPUT_P_INVALID, 0, \
UPUT_P_INVALID, 0, \
UPUT_P_INVALID, 0, \
__FILE__, __LINE__ , ## __VA_ARGS__)
See also Standard alternative to GCC's ##__VA_ARGS__ trick?. There's no standard workaround to this if you have to use preprocessors.

How do you create a debug only function that takes a variable argument list? Like printf()

I'd like to make a debug logging function with the same parameters as printf. But one that can be removed by the pre-processor during optimized builds.
For example:
Debug_Print("Warning: value %d > 3!\n", value);
I've looked at variadic macros but those aren't available on all platforms. gcc supports them, msvc does not.
I still do it the old way, by defining a macro (XTRACE, below) which correlates to either a no-op or a function call with a variable argument list. Internally, call vsnprintf so you can keep the printf syntax:
#include <stdio.h>
void XTrace0(LPCTSTR lpszText)
{
::OutputDebugString(lpszText);
}
void XTrace(LPCTSTR lpszFormat, ...)
{
va_list args;
va_start(args, lpszFormat);
int nBuf;
TCHAR szBuffer[512]; // get rid of this hard-coded buffer
nBuf = _vsnprintf(szBuffer, 511, lpszFormat, args);
::OutputDebugString(szBuffer);
va_end(args);
}
Then a typical #ifdef switch:
#ifdef _DEBUG
#define XTRACE XTrace
#else
#define XTRACE
#endif
Well that can be cleaned up quite a bit but it's the basic idea.
This is how I do debug print outs in C++. Define 'dout' (debug out) like this:
#ifdef DEBUG
#define dout cout
#else
#define dout 0 && cout
#endif
In the code I use 'dout' just like 'cout'.
dout << "in foobar with x= " << x << " and y= " << y << '\n';
If the preprocessor replaces 'dout' with '0 && cout' note that << has higher precedence than && and short-circuit evaluation of && makes the whole line evaluate to 0. Since the 0 is not used the compiler generates no code at all for that line.
Here's something that I do in C/C++. First off, you write a function that uses the varargs stuff (see the link in Stu's posting). Then do something like this:
int debug_printf( const char *fmt, ... );
#if defined( DEBUG )
#define DEBUG_PRINTF(x) debug_printf x
#else
#define DEBUG_PRINTF(x)
#endif
DEBUG_PRINTF(( "Format string that takes %s %s\n", "any number", "of args" ));
All you have to remember is to use double-parens when calling the debug function, and the whole line will get removed in non-DEBUG code.
Ah, vsprintf() was the thing I was missing. I can use this to pass the variable argument list directly to printf():
#include <stdarg.h>
#include <stdio.h>
void DBG_PrintImpl(char * format, ...)
{
char buffer[256];
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
printf("%s", buffer);
va_end(args);
}
Then wrap the whole thing in a macro.
Another fun way to stub out variadic functions is:
#define function sizeof
#CodingTheWheel:
There is one slight problem with your approach. Consider a call such as
XTRACE("x=%d", x);
This works fine in the debug build, but in the release build it will expand to:
("x=%d", x);
Which is perfectly legitimate C and will compile and usually run without side-effects but generates unnecessary code. The approach I usually use to eliminate that problem is:
Make the XTrace function return an int (just return 0, the return value doesn't matter)
Change the #define in the #else clause to:
0 && XTrace
Now the release version will expand to:
0 && XTrace("x=%d", x);
and any decent optimizer will throw away the whole thing since short-circuit evaluation would have prevented anything after the && from ever being executed.
Of course, just as I wrote that last sentence, I realized that perhaps the original form might be optimized away too and in the case of side effects, such as function calls passed as parameters to XTrace, it might be a better solution since it will make sure that debug and release versions will behave the same.
In C++ you can use the streaming operator to simplify things:
#if defined _DEBUG
class Trace
{
public:
static Trace &GetTrace () { static Trace trace; return trace; }
Trace &operator << (int value) { /* output int */ return *this; }
Trace &operator << (short value) { /* output short */ return *this; }
Trace &operator << (Trace &(*function)(Trace &trace)) { return function (*this); }
static Trace &Endl (Trace &trace) { /* write newline and flush output */ return trace; }
// and so on
};
#define TRACE(message) Trace::GetTrace () << message << Trace::Endl
#else
#define TRACE(message)
#endif
and use it like:
void Function (int param1, short param2)
{
TRACE ("param1 = " << param1 << ", param2 = " << param2);
}
You can then implement customised trace output for classes in much the same way you would do it for outputting to std::cout.
What platforms are they not available on? stdarg is part of the standard library:
http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html
Any platform not providing it is not a standard C implementation (or very, very old). For those, you will have to use varargs:
http://opengroup.org/onlinepubs/007908775/xsh/varargs.h.html
Part of the problem with this kind of functionality is that often it requires
variadic macros. These were standardized fairly recently(C99), and lots of
old C compilers do not support the standard, or have their own special work
around.
Below is a debug header I wrote that has several cool features:
Supports C99 and C89 syntax for debug macros
Enable/Disable output based on function argument
Output to file descriptor(file io)
Note: For some reason I had some slight code formatting problems.
#ifndef _DEBUG_H_
#define _DEBUG_H_
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "stdarg.h"
#include "stdio.h"
#define ENABLE 1
#define DISABLE 0
extern FILE* debug_fd;
int debug_file_init(char *file);
int debug_file_close(void);
#if HAVE_C99
#define PRINT(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, format, ##__VA_ARGS__); \
} \
else { \
fprintf(stdout, format, ##__VA_ARGS__); \
} \
}
#else
void PRINT(int enable, char *fmt, ...);
#endif
#if _DEBUG
#if HAVE_C99
#define DEBUG(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, "%s : %d " format, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
else { \
fprintf(stderr, "%s : %d " format, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
}
#define DEBUGPRINT(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, format, ##__VA_ARGS__); \
} \
else { \
fprintf(stderr, format, ##__VA_ARGS__); \
} \
}
#else /* HAVE_C99 */
void DEBUG(int enable, char *fmt, ...);
void DEBUGPRINT(int enable, char *fmt, ...);
#endif /* HAVE_C99 */
#else /* _DEBUG */
#define DEBUG(x, format, ...)
#define DEBUGPRINT(x, format, ...)
#endif /* _DEBUG */
#endif /* _DEBUG_H_ */
Have a look at this thread:
How to make a variadic macro (variable number of arguments)
It should answer your question.
This is what I use:
inline void DPRINTF(int level, char *format, ...)
{
# ifdef _DEBUG_LOG
va_list args;
va_start(args, format);
if(debugPrint & level) {
vfprintf(stdout, format, args);
}
va_end(args);
# endif /* _DEBUG_LOG */
}
which costs absolutely nothing at run-time when the _DEBUG_LOG flag is turned off.
This is a TCHAR version of user's answer, so it will work as ASCII (normal), or Unicode mode (more or less).
#define DEBUG_OUT( fmt, ...) DEBUG_OUT_TCHAR( \
TEXT(##fmt), ##__VA_ARGS__ )
#define DEBUG_OUT_TCHAR( fmt, ...) \
Trace( TEXT("[DEBUG]") #fmt, \
##__VA_ARGS__ )
void Trace(LPCTSTR format, ...)
{
LPTSTR OutputBuf;
OutputBuf = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, \
(size_t)(4096 * sizeof(TCHAR)));
va_list args;
va_start(args, format);
int nBuf;
_vstprintf_s(OutputBuf, 4095, format, args);
::OutputDebugString(OutputBuf);
va_end(args);
LocalFree(OutputBuf); // tyvm #sam shaw
}
I say, "more or less", because it won't automatically convert ASCII string arguments to WCHAR, but it should get you out of most Unicode scrapes without having to worry about wrapping the format string in TEXT() or preceding it with L.
Largely derived from MSDN: Retrieving the Last-Error Code
Not exactly what's asked in the question . But this code will be helpful for debugging purposes , it will print each variable's value along with it's name . This is completely type independent and supports variable number of arguments.
And can even display values of STL's nicely , given that you overload output operator for them
#define show(args...) describe(#args,args);
template<typename T>
void describe(string var_name,T value)
{
clog<<var_name<<" = "<<value<<" ";
}
template<typename T,typename... Args>
void describe(string var_names,T value,Args... args)
{
string::size_type pos = var_names.find(',');
string name = var_names.substr(0,pos);
var_names = var_names.substr(pos+1);
clog<<name<<" = "<<value<<" | ";
describe(var_names,args...);
}
Sample Use :
int main()
{
string a;
int b;
double c;
a="string here";
b = 7;
c= 3.14;
show(a,b,c);
}
Output :
a = string here | b = 7 | c = 3.14
Having come across the problem today, my solution is the following macro:
static TCHAR __DEBUG_BUF[1024];
#define DLog(fmt, ...) swprintf(__DEBUG_BUF, fmt, ##__VA_ARGS__); OutputDebugString(__DEBUG_BUF);
You can then call the function like this:
int value = 42;
DLog(L"The answer is: %d\n", value);