Q:

Cast to bool: `!!` vs `(bool)`

Is there any difference in using !!x vs (bool)x?
Assuming __STDC_VERSION__ >= 199901L and #include <stdbool.h>
Do both of them guarantee that the result is either 0 or 1, and that no overflow occurs, no matter the size and value of x?

A:

!!x (in C, not C++) has type int. (bool)x (with <stdbool.h> included) has type _Bool.
While _Bools are quick to be promoted to ints, the two can be told apart from inside a _Generic.
!!x (or the equivalent 0!=x) will always be either 0 or 1 and (bool)x will always be either (bool)0 or (bool)1 and if it compiles (=doesn't violate any constraints) and x is defined, it will always be well defined.
Overflow in expressions like !!x+INT_MAX or (bool)x+INT_MAX (bool promoted to int) is still a concern.

References:
6.3.1.2: (_Bool)x <=> (_Bool)(0!=x)

1 When any scalar value is converted to _Bool, the result is 0 if the
  value compares equal to 0; otherwise, the result is 1.59)

(
6.2.5p18, 6.2.5p21 -- scalars are numeric types or pointers

Integer and floating types are collectively called arithmetic types.
  ...
Arithmetic types and pointer types are collectively called scalar
  types. ...
  )

6.5.3.3p5: !!x <=> 0!=x

The result of the logical negation operator ! is 0 if the value of its
  operand compares unequal to 0, 1 if the value of its operand compares
  equal to 0. The result has type int. The expression !E is equivalent
  to (0==E).

