Detecting integer expressions of integers in macros

A macro was discussed on the Linux kernel mailing list to check if its argument is an integer constant expression and is a constant expression itself.

One particularly smart approach that doesn't use the built-in functions suggested by Martin Wecker (taking inspiration from glibc tgmath.h ):

#define ICE_P(x) (sizeof(int) == sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1))) 

This macro expands to an integer constant expression of value 1 if the argument is an integer constant expression, 0 otherwise. However, it relies on sizeof(void) for resolution (and differs from sizeof(int) ), which is an extension of GNU C.

Is it possible to write such a macro without built-in functions and not rely on language extensions? If so, does he evaluate his argument?


For an explanation of the macro shown above, see instead: Explain a macro that checks the expression of an integer constant

+30
source share
2 answers

Use the same idea where the type of the expression ?: Depends on whether the argument is a constant with a null pointer or normal void * , but it detects a type with _Generic :

 #define ICE_P(x) _Generic((1? (void *) ((x)*0) : (int *) 0), int*: 1, void*: 0) 

Demo on Ideone. _Generic is an addition to C11, so if you are stuck on C99 or something earlier, you will not be able to use it.

In addition, you have standard references for defining a null pointer constant and a way for null pointer constants to interact with an expression type ?: ::

An integer constant expression with a value of 0 or such an expression passed to the void * type is called a null pointer constant.

and

If both the second and third operands are pointers, and one is a constant of a null pointer, and the other is a pointer, the result type is a pointer to a type that corresponds to all type qualifiers of types that are referenced by both operands. In addition, if both operands are pointers to compatible types or to different versions of compatible types, the result type is a pointer to a suitable version of the composite type; if one operand is a null pointer constant, the result is of the type of another operand; otherwise, one operand is a pointer to void or a qualified version of void, in which case the result type is a pointer to a suitable version of void .

+22
source

I don't have a fix for sizeof(void) , which is not standard, but you can get around the possibility that sizeof(void) == sizeof(int) by doing something like:

 #define ICE_P(x) ( \ sizeof(void) != \ sizeof(*( \ 1 ? \ ((void*) ((x) * 0L) ) : \ ((struct { char v[sizeof(void) * 2]; } *) 1) \ ) \ ) \ ) 

I know this is not a complete answer, but it is a little closer ...

+16
source

Source: https://habr.com/ru/post/1276072/


All Articles