Home > Mobile >  What's the use of "(void)0" in __typeof__?
What's the use of "(void)0" in __typeof__?

Time:12-11

I am currently looking at the stdatomic.h header file in ubuntu linux.
What is the use of (void)0 and comma in __typeof__ ((void)0, *__atomic_store_ptr) ?
Doesn't this need nothing?

#define atomic_store_explicit(PTR, VAL, MO)             \
  __extension__                             \
  ({                                    \
    __auto_type __atomic_store_ptr = (PTR);             \
    __typeof__ ((void)0, *__atomic_store_ptr) __atomic_store_tmp = (VAL);   \
    __atomic_store (__atomic_store_ptr, &__atomic_store_tmp, (MO)); \
  })

CodePudding user response:

It will help when PTR happens to be a pointer to an array or a function or a pointer to a qualified type. The comma operator in ((void)0,x) will force L-value conversion. It basically means transforming an object into a value. In a case of arrays it transforms an array in to pointer to its first element. Functions that are transformed to function pointers. The qualified types looses qualifiers like volatile, const or _Atomic.

The l-value conversion happens in pretty much every case except address operator &, sizeof, _Alignof and gcc's __typeof__ (typeof in upcoming C23).

As it was said in the comments the cast to void is used to silence warning about unused value of 0.

  1. Pointer to an array

See:

int arr[3];
int (*ptr)[3];

atomic_store_explicit(ptr, &arr, XXX);

If no L-value conversion was forced then the macro would expand to:

__auto_type __atomic_store_ptr = (ptr);

which is

int (*__atomic_store_ptr)(ptr);

and

__typeof__ (*__atomic_store_ptr) __atomic_store_tmp = (VAL);

which becomes:

int __atomic_store_tmp[3] = arr;

because dereferencing int(*)[3] produces int[3].

It will cause compilation failure due to initialization of an array with a pointer.

With the trick the code above will become:

int *__atomic_store_tmp = arr;

because int[3] is transformed to int* by doing l-value conversion.

  1. Function pointer.

For function pointers the situation is analogous to a pointer to an array.

void foo(void);
void (*ptr)(void);

atomic_store_explicit(ptr, foo, X);

Expands to:

...
__auto_type __atomic_store_ptr = (PTR);

==>

void (*__atomic_store_ptr)(void) = ptr;

and

__typeof__ (*__atomic_store_ptr) __atomic_store_tmp = (VAL);

==>

void __atomic_store_tmp(void) = foo;

because dereferencing (void(*)(void) produces a function type void(void). The compilation fails due to initialization of a function with is not allowed in C.

With the trick the above declaration becomes:

void (*__atomic_store_tmp)(void) = foo;

which compiles fine.

  1. A pointer to a qualified type.

Assume:

volatile int *ptr;
atomic_store_explicit(ptr, 42, XXX);

Now:

__auto_type __atomic_store_ptr = (ptr);

==>

volatile int *__atomic_store_ptr = ptr;

and:

__typeof__ (*__atomic_store_ptr) __atomic_store_tmp = (val);

==>

volatile int __atomic_store_tmp = val;

Now the value becomes volatile causing subtle issues like worse performance. With l-value conversion the type of __atomic_store_tmp becomes unqualified int.

  •  Tags:  
  • c
  • Related