Search code examples
cbooleanbit-fieldsc89

How to insert booleans into a bitfield in C89


As far as I understand, in C89 all boolean expressions are of type integer. This also means that function parameters that represent bool usually get represented by an int parameter.

Now my question is how I can most ideally take such an int and put it into a bitfield so that it only occupies one bit (let's ignore padding for now).

The first thing here is which type to use. Using int or any other unsigned type doesn't work, because when there is only one bit, only -1 and 0 can be represented (at least with two's complement).

While -1 technically evaluates as true, this is not ideal because actually assigning it without undefined behavior can be quite tricky from what I understand.

So an unsigned type should be chosen for the bitfield:

typedef struct bitfield_with_boolean {
    unsigned int boolean : 1;
} bitfield_with_boolean;

The next question is then how to assign that bitfield. Just taking an int or similar won't work because the downcast truncates the value so if the lowest bit wasn't set, a value that would previously evaluate to true would now suddenly evaluate to false.

As far as I understand, the boolean operators are guaranteed to always return either 0 or 1. So my idea to solve this problem would be something like this:

#define to_boolean(expression) (!!(expression))

So in order to assign the value I would do:

bitfield_with_boolean to_bitfield(int boolean) {
    bitfield_with_boolean bitfield = {to_boolean(boolean)};

    return bitfield;
}

Is that correct, and or is there a better way?

NOTE:

I know the problem is completely solved starting with C99 because casting to _Bool is guaranteed to always result in either a 0 or a 1. Where 0 is only the result if the input had a value of 0.


Solution

  • Yes, your solution is correct. However, I wouldn't hide it behind a macro, and I wouldn't name a macro using all_lowercase letters.

    !!var is sufficiently idiomatic that I'd say it's fine in code.

    Alternatives include var != 0 and, of course, var ? 1 : 0.