stdbool.h

Discussion in 'C Programming' started by Jorgen Grahn, Mar 1, 2014.

  1. No I'm not.
    I still don't get it. Why is SetControlState(true) any more confusing
    that SetControlState(1) or SetControlState(42)?

    I argued that this is a general problem: magic constants are almost
    always a bad idea and that applies to true and false as much as to 0 or
    42. I made a subsidiary remark that there are some cases where we don't
    mind: i+1 and set_bit(n, true) both seem reasonable to me.

    Is your point that API designers are somehow tempted into not providing
    explanatory names for some Boolean parameters where they would have
    thought to do so for integer ones? If so, I won't argue the point --
    that may be the case, and I have no evidence one way or the other.
     
    Ben Bacarisse, Mar 4, 2014
    #41
    1. Advertisements

  2. I think you guys are discussing a metaphysical problem. It all depends on the
    project and the people who are participating, but in general I tend to use a
    more pragmatic approach.

    boolean variables make sense as arguments and as return values. If used as an
    argument the function name is more important than the argument name itself.

    e.g.:

    SetControlState(true) <=> UnsetControlState(false)
    UnsetControlState(true) <=> SetControlState(false)

    Fact is that I can represent more than 2 states with magic constants, with
    booleans there are only 2 states: on/off, true/false, yes/no. So depending on
    the situation one concept is always more beneficial than the other.

    Just my 2 cents.

    --
    Helmut K. C. Tessarek

    /*
    Thou shalt not follow the NULL pointer for chaos and madness
    await thee at its end.
    */
     
    Helmut Tessarek, Mar 4, 2014
    #42
    1. Advertisements

  3. Jorgen Grahn

    Tim Rentsch Guest

    I must admit to a certain uneasiness to using 'true' and 'false'
    as what are essentially manifest constants. They look too much
    like they might be variables; in C programs, TRUE and FALSE seem
    more in keeping with the culture. (Using 'bool' as a type name
    is probably okay.)

    Having said that, if you want to introduce 'bool', 'true', and
    'false' into C99 programs, go ahead and do that. However, I
    would suggest not using <stdbool.h> but rather defining the three
    names yourself (in a regular header file) without using the
    preprocessor, eg,

    typedef _Bool bool;
    enum { true = 1, false = 0 };

    In C++, bool, true, and false are part of the language, and
    always have the same meaning. In C, <stdbool.h> defines
    these names as macros. Besides possibly interfering with
    otherwise perfectly reasonable local uses, defining the
    names as macros is likely to produce rather cryptic error
    messages (or worse?) in cases where these names are used
    in ways not in keeping with the #define'd values. Defining
    the names as regular identifiers rather than preprocessor
    names avoids these problems.

    One other comment: if you do use 'bool', it should always
    be a synonym for _Bool, never for another integer type,
    because of the different semantics involved. I expect you
    are already of the same opinion, but I believe the point
    bears repeating for those who have not yet had the pleasure
    of encountering problems that might ensue from confusing
    the different semantics involved.
     
    Tim Rentsch, Mar 9, 2014
    #43
  4. Jorgen Grahn

    David Brown Guest

    All-caps may be in common use in C, but that does not make it a good
    idea. It is a relic from the days of computers without small letters,
    and from before C had "const" or "enum".

    In the modern world, "true" and "false" do not look like variables
    because the choice of name makes it obvious, because the compiler will
    enforce their consistency, and because there is a good chance that your
    editor will pick fonts, colours, or other context-sensitive information
    showing them to be constants. We don't need our software to shout at us
    by using all-caps, nor draw unnecessary attention to the use of
    particular identifiers.

    I see no justification for this idea. These identifiers are part of the
    C language, as provided in the standards-mandated standard header.
    Making your own versions is at best a duplication of effort, at worst it
    is an invitation to people to invent their own implementation of these
    symbols.
    The C language - rightly or wrongly - defines _Bool to be a type large
    enough to store the values 0 and 1. It is not an enumerated type. I
    think it might have been advantageous to define it as "typedef enum {
    false = 0, true = 1 } bool;", or to introduce new keywords like in C++.
    But that is not the way it was done. That is (I presume) why the
    standards say that these identifiers be macros.

    I can't imagine any "perfectly reasonable local uses" of bool, true or
    false that conflict with this, nor can I imagine any cryptic error
    messages as a result. If you can provide examples, maybe I'll change my
    mind.
     
    David Brown, Mar 9, 2014
    #44
  5. Jorgen Grahn

    jacob navia Guest

    Le 10/03/2014 00:22, David Brown a écrit :
    I would second that.

    Can you give an example Tim?

    I agree with David also that is a bad idea not to use the standard
    header. I just do not see the problem that could arise.
     
    jacob navia, Mar 10, 2014
    #45
  6. Use of all-caps *for macros* is still a good idea, because of the
    potential they have to do violence to the language syntax and semantics.
    Consider, for example:

    #define MAX(x, y) ( (x) >= (y) ? (x) : (y) )

    The all-caps name makes it clear that something odd could be going on --
    in this case, that one of the arguments will be evaluated twice.

    And it's a well established convention (though one that the standard
    library doesn't consistently follow).
    I agree. For a compiler without _Bool, my favorite way to define a
    boolean type is

    typedef enum { false, true } bool;

    There is a significant difference between an enum type and _Bool;
    conversion to the latter can only yield 0 or 1 (barring undefined
    behavior). Though I try to avoid writing code that depends on that
    (more for the sake of clarity than for portability).

    The obvious way to introduce a boolean type to the language would have
    been the C++ approach, making bool, false, and true all keywords. But
    that would have broken existing code. The existing solution (adding
    _Bool as a built-in type, and bool, false, and true as macros in
    <stdbool.h>) is probably about the best that could have been done given
    that constraint. (Though I would have made bool a typedef rather than a
    macro.)

    [...]
     
    Keith Thompson, Mar 10, 2014
    #46
  7. Jorgen Grahn

    James Kuyper Guest

    A naming convention that reserves upper case for one purpose and lower
    case for other purposes (and it is precisely such a convention that Tim
    was referring to) cannot be explained by reference back to the days when
    only one case was available. It requires a minimum of two different
    cases in order to follow such a convention.
     
    James Kuyper, Mar 10, 2014
    #47
  8. Jorgen Grahn

    ais523 Guest

    I'm not Tim, but on some code I'm maintaining (that actually originally
    predates C89; prototypes were only added to it recently), "bool" is a
    typedef for some sort of char (not sure offhand whether it's signed,
    unsigned, or plain), and structures are serialized using the equivalent
    of fread/fwrite (a dubious practice that means that the serialization
    format cannot easily be changed, and which also introduces
    implementation-dependent behaviour for no good reason). Occasionally,
    the original programmers ended up needing to store additional
    information in the serialization format, without breaking backwards
    compatibility; and their approach was to use the "spare bits" in the
    booleans!

    If I replaced the char-style booleans with _Bool in that codebase, it
    would cause some subtle breakage that might not be noticed immediately
    (although the compiler might be clever enough to notice a bitwise-and of
    a _Bool against 2 and produce a diagnostic; I haven't tested that), in
    that the extra bits wouldn't fit into a _Bool in a sensible way (all the
    offending fields would have to be identified and converted to unsigned
    char, most likely). I'm not even sure what happens if you fread an
    inappropriate bit pattern into a _Bool, offhand (it wouldn't surprise me
    if that were undefined behaviour).
     
    ais523, Mar 10, 2014
    #48
  9. Jorgen Grahn

    David Brown Guest

    That's fair enough - you are dealing with pre-C99 code. It is not
    surprising that the it has its own definitions for bool, true and false
    that could conflict with the C99 standard ones. (The original question
    started "I'm sitting with a C99 code base and thinking about introducing
    <stdbool.h>".)

    I am not sure that the usage here is "perfectly reasonable local uses",
    certainly by C99 standards, but I guess that's a matter of taste.
     
    David Brown, Mar 10, 2014
    #49
  10. Jorgen Grahn

    David Brown Guest

    There is a simple answer here - don't write code that has side effects
    inside function arguments (such as MAX(x++, y++)). Also, avoid writing
    general function-like macros that might cause trouble if people /do/
    call them with side-effect arguments. With modern C, static inline
    functions can replace many function-like macros with a clearer and safer
    alternative. And if you really need generic handling of different
    types, there are several possibilities (gcc "typeof", C11 _Generic, C++
    templates) - although these all have obvious disadvantages.
    It is an established convention, but that does not make it a good thing
    (although clearly it has the advantage that people will be unsurprised
    by it).

    I can find no valid reason - beyond "history" and "convention" - to make
    style distinctions:

    #define MAX_NUMBER_OF_ITEMS 10
    static const int max_number_of_items = 10;
    enum { max_number_of_items = 10 };

    In most cases, these three identifiers can be used in the same way and
    the same places, give the same resulting code, and have the same
    compiler-enforced read-only nature. Why should one of them be in
    all-caps, making it stand out far too much in the source code?


    If I have a piece of code that has a MAX() macro, and I replace the
    macro definition with a static inline function, should I go through all
    the code and change "MAX(..)" to "max(..)" just because the macro has
    turned into a function - even though it does exactly the same thing, and
    generates exactly the same code? Conversely, if I want to change an
    existing function into a macro do I then need to rename everything in
    all-caps just to follow this convention?


    I understand that many people use this convention, and I understand that
    people think it gives them some sort of warning or protection against
    mistakes with macros. I just don't agree with it - at least, not in
    /my/ code. (And I know my view here is controversial.)
    Fair enough.
    I too would have had bool as a typedef - and false and true as
    enumeration constants rather than macros (but as you noted above, bool
    itself cannot be an enum). Perhaps the language could have defined
    _True and _False as keywords for the type, equivalent to C++'s keywords,
    and then put macros in <stdbool.h> to define true and false as _True and
    _False rather than 1 and 0. But then the standards people might have
    been tempted to say that the values of _True and _False, when converted
    to integers, were implementation defined....
     
    David Brown, Mar 10, 2014
    #50
  11. Jorgen Grahn

    BartC Guest

    This is far too sensible a point of view for comp.lang.c!

    I don't like uses of upper case like this because it make code ugly.

    (Also it encourages people to use upper and lower case versions of the same
    name for different purposes. I know many will see that as an advantage.
    Although that is more a consequence of C being case-sensitive.)

    As for the MAX macro that is always brought up as an example, why doesn't
    someone just throw in some actual min/max functions (or ideally, operators)
    into the language! That's if they are not in there already; I'm never quite
    sure.
     
    BartC, Mar 10, 2014
    #51
  12. Jorgen Grahn

    David Brown Guest

    gcc had max and min operators as extensions, but I believe they are
    deprecated these days.

    There is no way that C could introduce min and max as operators or
    keywords - it would cause too many conflicts. It would be possible to
    add them to a standard library header - it wouldn't need anything more
    than a _Generic macro such as those in <tgmath.h>. It would fit well in
    <stdlib.h>, where the abs() and div functions could also nicely be
    replaced with _Generics.

    On the other hand, if max() and min() were added as safe macros or
    functions in some way, what then could be use as an example of the
    dangers of side effects combined with macros? (Or am I being too
    cynical? :)
     
    David Brown, Mar 10, 2014
    #52
  13. Jorgen Grahn

    Stefan Ram Guest

    Such an approach was also taken in early LISP
    implementations, where a bit in a word indicated whether the
    rest was an integer or a pointer IIRC. And I must admit that
    this feels quite natural to me.

    How would you implement a binary tree node whose leafs can
    be small integers in a memory-efficient way?

    union cr;
    struct node { union cr left; union cr right; }
    union cr { int value; struct node * pointer; };
    ispointer( union cr * cr ) { return ????; }

    Assume that you would know that on your architecture one bit
    of a pointer lways is zero and that you only have very
    little memory available. Wouldn't it be tempting, when you
    are developing for a special hardware?
     
    Stefan Ram, Mar 10, 2014
    #53
  14. That's fine if the author of the macro definition and the author of
    any code that uses it are the same person. I don't particularly
    like side effects in function arguments, but it's not practical
    to ban them -- and sometimes something like func(count++) is more
    convenient than the alternative. An all-caps macro name is a
    reminder to *avoid* arguments side effects.

    If you're writing a header to be used by other programmers, and you
    feel the need to define macros in that header, it's probably a good
    idea to follow the conventions those other programmers are likely
    to understand. (And yes, that's a slightly more sophisticated
    version of "do it that way because I said so".)

    Static inline functions can't replace MAX and MIN, which work for any
    type with a ">=" operator. gcc's "typeof" is obviously not portable,
    and template are not C. I suppose you could use _Generic in a macro
    definition along with a collection of N functions to implement max
    and min for N different types, but I don't think it would handle
    arguments of different types.

    In any case, if you're using something other than macros, the
    all-caps convention isn't even relevant.
    Most but not all. The name of a "static const int" object isn't a
    constant expression, and an enumeration constant can only be of type
    int.

    If I see a reference to "max_number_of_items" without seeing its
    definition, I'm likely to assume that it's a variable whose value might
    be determined at execution time. If I see MAX_NUMBER_OF_ITEMS, I'll
    assume it's a compile-time constant. The use of all-caps does convey
    useful information to the reader. (Which admittedly doesn't cover the
    enum case; I never claimed any of this was 100% consistent.)
    If you want to follow the convention strictly, yes. But it's only a
    convention, and you don't have to follow it in your own code if you
    don't want to.
    Making false and true (however they're defined) be of type _Bool/bool
    would have been clean, but given C's rather, um, promiscuous implicit
    conversions it wouldn't have made any difference 99% of the time.
    Making them have type int is consistent with the treatment of both
    character constants and enumeration constants.

    I don't think there would have been any temptation to make the results
    of conversions implementation-defined. Conversions of _Bool values to
    integer types are well defined anyway -- and in fact _Bool *is* an
    integer type.
     
    Keith Thompson, Mar 10, 2014
    #54
  15. Jorgen Grahn

    Tim Rentsch Guest

    Do you mean you don't see a possible advantage to defining an
    identifier as a typedef or enum value rather than a macro?
    Or that you can't think of such a situation that would apply
    in the particular case of bool, true, or false?
     
    Tim Rentsch, Mar 10, 2014
    #55
  16. Jorgen Grahn

    David Brown Guest

    You said:

    "In C++, bool, true, and false are part of the language, and
    always have the same meaning. In C, <stdbool.h> defines
    these names as macros. Besides possibly interfering with
    otherwise perfectly reasonable local uses, defining the
    names as macros is likely to produce rather cryptic error
    messages (or worse?) in cases where these names are used
    in ways not in keeping with the #define'd values. Defining
    the names as regular identifiers rather than preprocessor
    names avoids these problems."

    We would like to see examples of such problems, or at least ideas about
    how the standard macro definitions could cause problems while an enum
    based one would avoid the problems - all within "perfectly reasonable"
    code. /I/ can't think of any cases - so it would help me understand
    your point if you could elaborate here.

    David
     
    David Brown, Mar 10, 2014
    #56
  17. Jorgen Grahn

    ais523 Guest

    Yes, that might be necessary, but I wouldn't claim that the resulting
    code was anything like portable, standards-compliant C. I've written
    C programs for processors with only a few kilobytes of memory before
    now, some parts of which were sufficiently time-sensitive that I had
    the assembler output open in another window and tweaked the input C
    until the compiler produced the output I wanted. I don't really think
    of that as C, though (at least partly because the compilers for such
    architectures tend to be limited and buggy and full of extensions).
    It's a language that's accepted by at least one C implementation, but
    it's impossible to get it anywhere close to strictly conforming.

    In the specific case of binary trees, I probaby wouldn't use something
    as wasteful as pointers on such a limited system. Although the compilers
    can handle pointers just fine, there isn't really room for a functioning
    malloc system, so you're best off using a static array to store your
    tree and using indexes into the array as your pointer-equivalents. (Or,
    if the tree is approximately balanced, using an entirely different
    storage method, such as is often used for heaps.)

    I've also been burned by nonportable code plenty of times in the past.
    Right now, when writing C, I aim for compliance with the standards if at
    all possible; pretty much my minimum standard of portability for new
    projects is "the code, minus any libraries it needs to run, is strictly
    conforming C11; and any features in the code that weren't in C89 must
    have been supported as extensions in gcc and clang for the last
    several years". Typically I also rely on POSIX for the supporting
    libraries when possible, and try to confine it to a minimum of files.
     
    ais523, Mar 10, 2014
    #57
  18. Jorgen Grahn

    jacob navia Guest

    Le 10/03/2014 18:12, Tim Rentsch a écrit :
    Not in this case, no. That's why I asked the question that you don't
    actually answer.

    One advantage of the macro is that you can undefine it. You can't do
    that with a typedef.
    No, I can't, and I think you can't either...

    :)
     
    jacob navia, Mar 10, 2014
    #58
  19. Jorgen Grahn

    Eric Sosman Guest

    Someone I used to know once did that trick with a big array
    of function pointers. Since function pointers always point to
    the function's first instruction, and since instructions always
    start on word boundaries (he "knew" this to be true, understand?),
    he used the low-order pointer bit as a flag to indicate which
    functions actually needed to run on the current pass and which
    could be skipped.

    I discovered this awfulness when porting his code to the VAX,
    on which *neither* of the things he "knew" held true ...
     
    Eric Sosman, Mar 10, 2014
    #59
  20. Jorgen Grahn

    Tim Rentsch Guest

    Different developers have different opinions on that point, but
    in any case it's irrelevant to what I was saying.
    Nonsense, as James Kuyper has pointed out.
    That has no bearing on my comment.
    Are you always so parochial? Is it so hard for you to imagine
    that other developers might have different opinions on these
    topics?
    The header <stdbool.h> is part of a standard implementation, but
    use of <stdbool.h> is optional, not mandatory. Moreover, the
    Standard gives explicit and specific permission to undefine the
    macros bool, true, and false from <stdbool.h>, so obviously the
    Standard anticipates that some developers would want to do that
    for one or more of those symbols, and perhaps define their own
    You're engaging in hyperbole. What I am doing is pointing out
    alternate definitions for bool, true, and false, with somewhat
    different characteristics for how the identifiers can be used,
    that may be preferable in some circumstances. If some
    developers find that their own circumstances favor those
    different characteristics, they may reasonably prefer to use
    those alternate definitions; in other circumstances they may
    reasonably prefer to use the <stdbool.h> definitions. The
    choice is up to them. Under some circumstances (which I will
    not describe), I would advocate using using the <stdbool.h>
    definitions; in others I would advocate using the alternate
    definitions mentioned above. IMO this question should not be
    given a "one size fits all" kind of answer.
    The idea that bool might or should be an enumerated type has
    no bearing on my comments.
    I think you have missed the point of what I've been saying. In
    any case I cannot be responsible for your lack of imagination.
     
    Tim Rentsch, Mar 10, 2014
    #60
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.