Reputation: 3371
I have been thinking about ways to validate types in C macros and so far the best way that I have come up with is this:
#define ASSERT_PTYPE(TYPE, VALUE) (0 && (*(int (*)(TYPE*))0)(VALUE))
This obviously expects a type name and a pointer to that type. A similar ASSERT_TYPE macro can be made as well. This seems to work quite well with GCC. It even gives a very helpful error message in the case that the types do not match. The problems are that I am not completely certain that this is valid C or the best way for that matter.
As I understand it the standard says that you can cast a function pointer, but the result of calling the cast function pointer is undefined. In this case it is impossible for the function to be called at runtime. Is that good enough or does the standard mean that you cannot even write code that cannot be called that calls the cast function?
Upvotes: 13
Views: 3282
Reputation: 78973
With C99 and compound literals you can do something like
#define ASSERT_TYPE(TYPE, VALUE) ((TYPE){ 0 } = (VALUE))
This ensures that VALUE
is assignment compatible to TYPE
. The expression returns an rvalue because of the assignment.
Compound literals work in function scope as well as in file scope and any decent compiler should optimize the extra object that is created out of the way.
Addition: TYPE
in that macro can be any valid type name, e.g pointer double*
, struct or union struct toto
, besides arrays. Array type such as double[4]
wouldn't work because of the assignment. Use pointer to
array double(*)[4]
instead, e.g as in
double A[4];
(*ASSERT_TYPE(double(*)[4], &A))
where the second line again is a lvalue of type double[4]
that is compile time checked for that property.
Upvotes: 12