Search code examples
cgccclanglanguage-lawyer

__builtin_types_compatible_p(t1, t2) and pointers to qualified types


The gcc documentation says that __builtin_types_compatible_p(t1, t2) "ignores top level qualifiers (e.g. const, volatile)", and indeed it does:

__builtin_types_compatible_p(int, const int)     returns 1
__builtin_types_compatible_p(int, volatile int)  also returns 1

I do not know what it means by "top level qualifiers", but pointers to things-which-are-compatible, are reported as not compatible:

__builtin_types_compatible_p(int *, const int *)     returns 0
__builtin_types_compatible_p(int *, volatile int *)  also returns 0
__builtin_types_compatible_p(void *, void *)         returns 1
__builtin_types_compatible_p(void *, const void *)   returns 0

which is, frankly, a surprise :-(

Can anyone provide a reason for this ? [Is my surprise a symptom of ignorance ?]


FWIW: I can work around this using __typeof__(), thus:

__builtin_types_compatible_p(__typeof__(*(void*)0), __typeof__(*(const void*)0))) returns 1

typedef int*       pi_t ;
typedef const int* pic_t ;
__builtin_types_compatible_p(__typeof__(*(pi_t)0), __typeof__(*(pic_t)0))) returns 1

Since __typeof__() accepts both an expression and a type, I have a macro:

#define Types_Compatible(_a, _b) \
  __builtin_types_compatible_p(__typeof__(_a), __typeof__(_b)) 

to slightly reduce the clutter.


Solution

  • int and const int are compatible as everywhere an int is expected (eg as a function parameter) a const int can be given. And, importantly, vice versa. The const and volatile only affect the variable, not the value.

    That is not the case for int* and const int*. If a function requires an int* you can not supply a const int*. If you try that you will get an 'incompatible types' error. For pointers the const and volatile refer to the value, not the variable. (In most cases, it depends on where you put the const)

    And your "workaround" just derefences the pointer so it gets rid of the pointer, so it ultimately answers a different question. It determines if the types pointed to are compatible, which is different from the pointer type itself.