2
  • I use the GCC compiler (version 9.2.0)
  • I want to use the typeof function in C but it raises an error (error: expected expression before 'typeof')
  • If you need more info, just ask me .
int a = 5;
double b;
//the expected result is "0", but it raises an error instead...
printf("%d", typeof(a) == typeof(b));

Lundin
  • 195,001
  • 40
  • 254
  • 396
Mobento
  • 71
  • 6

2 Answers2

3

You can get the behavior you want by dropping gcc extensions and using standard C _Generic:

#define my_typeof(x) _Generic((x), int: 1, double: 2)

printf("%d", my_typeof(a) == my_typeof(b));

The only catch is that you have to type out support for every type manually.

Lundin
  • 195,001
  • 40
  • 254
  • 396
3

GCC has a built-in function called __builtin_types_compatible_p that takes two arguments that are types (not expressions) and returns the int value 1 if the types are compatible, or 0 if they are incompatible.

OP's example could be written as:

int a = 5;
double b;
printf("%d", __builtin_types_compatible_p(typeof(a), typeof(b)));

From the online documentation:

Built-in Function: int __builtin_types_compatible_p (type1, type2)

You can use the built-in function __builtin_types_compatible_p to determine whether two types are the same.

This built-in function returns 1 if the unqualified versions of the types type1 and type2 (which are types, not expressions) are compatible, 0 otherwise. The result of this built-in function can be used in integer constant expressions.

This built-in function ignores top level qualifiers (e.g., const, volatile). For example, int is equivalent to const int.

The type int[] and int[5] are compatible. On the other hand, int and char * are not compatible, even if the size of their types, on the particular architecture are the same. Also, the amount of pointer indirection is taken into account when determining similarity. Consequently, short * is not similar to short **. Furthermore, two types that are typedefed are considered compatible if their underlying types are compatible.

An enum type is not considered to be compatible with another enum type even if both are compatible with the same integer type; this is what the C standard specifies. For example, enum {foo, bar} is not similar to enum {hot, dog}.

You typically use this function in code whose execution varies depending on the arguments’ types. For example:

#define foo(x)                                                  \
   ({                                                           \
    typeof (x) tmp = (x);                                       \
    if (__builtin_types_compatible_p (typeof (x), long double)) \
      tmp = foo_long_double (tmp);                              \
    else if (__builtin_types_compatible_p (typeof (x), double)) \
      tmp = foo_double (tmp);                                   \
    else if (__builtin_types_compatible_p (typeof (x), float))  \
      tmp = foo_float (tmp);                                    \
    else                                                        \
      abort ();                                                 \
    tmp;                                                        \
   })

Note: This construct is only available for C.

Ian Abbott
  • 15,083
  • 19
  • 33