Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to verify a type in a C macro

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?

like image 678
ltc Avatar asked Mar 18 '11 08:03

ltc


People also ask

Is type checking done in macro?

In macros, no type checking(incompatible operand, etc.) is done and thus use of macros can lead to errors/side-effects in some cases. However, this is not the case with functions. Also, macros do not check for compilation error (if any).

How do you check if a macro is defined in C?

Inside of a C source file, you can use the #ifdef macro to check if a macro is defined.

What does ## mean in C macro?

The double-number-sign or token-pasting operator (##), which is sometimes called the merging or combining operator, is used in both object-like and function-like macros. It permits separate tokens to be joined into a single token, and therefore, can't be the first or last token in the macro definition.

What is the data type of macro in C?

There are two kinds of macros. They differ mostly in what they look like when they are used. Object-like macros resemble data objects when used, function-like macros resemble function calls. You may define any valid identifier as a macro, even if it is a C keyword.


1 Answers

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.

like image 117
Jens Gustedt Avatar answered Oct 11 '22 21:10

Jens Gustedt