Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C11_Generic deduces true and false as integers

Tags:

c

generics

c11

In C11 there is the _Generic macro that can allow for cool generic functions. However using true and false with this results in incorrect deduction in the normal case:

#include <stdio.h>
#include <stdbool.h>

#define TypeName(x) \
  _Generic((x), \
    bool: "bool", \
    int: "int", \
    default: "unknown")

#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && (__bool_true_false_are_defined)
# undef true
# define true ((bool)(1))
# undef false
# define false ((bool)(0))
#endif

int main(void)
{
    printf("1: %s\n", TypeName(1));
    printf("true: %s\n", TypeName(true));
    printf("false: %s\n", TypeName(false));
}

This prints:

1: int
true: bool
false: bool

However without the middle bit that redefines true and false:

1: int
true: int
false: int

Which means you cannot do _Generic functions such as:

struct Variant * const int32 = variant_create(1);
struct Variant * const boolean = variant_create(true);

So my questions are:

  • Is the redefinition snippet a safe thing to do?
  • Is this an oversight in the C11 standard or a bug in GCC and Clang?
like image 253
Matt Clarkson Avatar asked Jan 09 '15 11:01

Matt Clarkson


2 Answers

Both types are indeed macros:

7.18 Boolean type and values

  1. The remaining three macros are suitable for use in #if preprocessing directives.
    They are:
    true which expands to the integer constant 1,
    false which expands to the integer constant 0,
    and
    __bool_true_false_are_defined which expands to the integer constant 1.

The last rule says you are allowed to redefine the macro:

  1. Notwithstanding the provisions of 7.1.3, a program may undefine and perhaps then redefine the macros bool, true, and false. 259)

    259) See ‘‘future library directions’’ (7.31.9)

in spite of the referenced rule :

7.1.3 Reserved identifiers

  1. If the program removes (with #undef) any macro definition of an identifier in the first group listed above, the behavior is undefined.

The rule 7.31.9 says redefining might not be a good idea:

7.31.9 Boolean type and values

  1. The ability to undefine and perhaps then redefine the macros bool, true, and false is an obsolescent feature.

So I suggest you create your own my_true and my_false macros which are cast to _Bool.

like image 152
2501 Avatar answered Sep 20 '22 16:09

2501


That's because true and false in stdbool.h are just integers 1 and 0, their types are indeed int, not bool.

C11 §7.18 Boolean type and values <stdbool.h>

The remaining three macros are suitable for use in #if preprocessing directives. They are

true

which expands to the integer constant 1,

false

which expands to the integer constant 0, and

__bool_true_false_are_defined

which expands to the integer constant 1.

like image 38
Yu Hao Avatar answered Sep 20 '22 16:09

Yu Hao