Typecast all arguments in a variadic macro

469 views Asked by At

I want to use sscanf to parse a long string ..
The data to be parsed will be stored in a struct whose members are all of the type time_t.
Unfortunately, there isn't any format string to mark a time_t so I'm just going to typecast all time_t * arguments as unsigned long long *, and because its a very long string with lots of arguments, typecasting each argument one by one will only mess my editor screen ..

So, I created a macro to simplify this:

#define typecast(type, ...) (type) __VA_ARGS__

And I invoked it like this:

sscanf(string, PARSE_STRING,
    typecast(unsigned long long *, /* my arguments */));

I though this would expand to:

sscanf(string, PARSE_STRING,
    (unsigned long long *) /* arg1 */, (unsigned long long *) /* arg2 */, /* and so on */);

But after inspecting with gcc -E, I found it expanded to this:

sscanf(string, PARSE_STRING,
    (unsigned long long *) /* arg1 */, /* arg2 */, /* and so on */));

How can I achieve my desired expansion functionality using variadic functions ?

2

There are 2 answers

1
BLUEPIXY On BEST ANSWER

use boost

#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>

#define CAMMA(r, data, i, elem) BOOST_PP_COMMA_IF(i)elem
#define CAST(r, data, elem) (data)elem
#define typecast(type, ...) BOOST_PP_SEQ_FOR_EACH_I(CAMMA, , BOOST_PP_SEQ_TRANSFORM(CAST, type, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))
0
Marian On

I have seen C preprocessor code looping over arguments of variadic macros and I wouldn't want it in my code. However, in your case, you can take the following solution. I am presenting macros which work for up to 4 arguments, you will surely be able to extend it to any constant.

#define typecast4(type, a1, a2, a3, a4, ...) ((type)a1), ((type)a2), ((type)a3), ((type)a4)
#define typecast(type, ...) typecast4(type, __VA_ARGS__, NULL, NULL, NULL, NULL)

This particular solution generates 4 arguments always. Note that, in your case, this does not matter because scanf accepts and safely ignores any arguments beyond the entered format. So, the following code compiles:

int main() {
  time_t x,y;
  scanf("%lld, %lld", typecast(long long *, &x, &y));
  ...
}

However, I am worrying about the cast from time_t * to long long *. It is written nowhere that time_t must be represented by long long. If it is represented by int on some platform the previous code will be buggy. The correct way to scan your values would be something like:

int main() {
  time_t x,y;
  long long lx, ly;
  scanf("%lld, %lld", &lx, &ly);
  x = lx;
  y = ly;
  ...
}

which is more correct and does not require any variadic macro.