1

Suppose I have two functions which may have side effects, and return boolean values. (with bool as defined in <stdbool.h>, so that defines bool as the _Bool type)

bool tweedledee(MyState *pmystate);
bool tweedledum(MyState *pmystate);

Is it safe to use bitwise operators to combine them?

bool both_tweedles = tweedledee(&mystate) & tweedledum(&mystate);

or

bool either_tweedle = tweedledee(&mystate) | tweedledum(&mystate);

I would traditionally use the logical operators && or ||; I'm working on a project where my team members are using the bitwise operators, since the functions may have side effects, and we want both function calls to occur. (The logical operators are short-circuiting.)

My only reservation is that I'm not sure whether a function returning bool can safely be assumed to return 1 and 0, rather than something else as an alternate value for true.


Just as an example: what if someone evil implemented them as follows?

bool tweedledee(MyState *pmystate)
{
   return 66;
}

bool tweedledum(MyState *pmystate)
{
   return 33;
}

then 66 & 33 is 0, and 66 | 33 is 99.

Jason S
  • 184,598
  • 164
  • 608
  • 970
  • this can help http://stackoverflow.com/questions/4276207/is-c-c-bool-type-always-guaranteed-to-be-0-or-1-when-typecasted-to-int I think that in c the bool is macro. so the answer is yes you can. – Alon Jul 23 '15 at 23:11
  • From the C99 standard: When any scalar value is converted to `_Bool`, the result is 0 if the value compares equal to 0; otherwise, the result is 1. `bool` expands to `_Bool` in ``: `#define bool _Bool`. – David Ranieri Jul 23 '15 at 23:16
  • 3
    While the bitwise combination of bools is safe, the order in which the operands are evaluated is unspecified, so one compiler might call tweedledee first and then tweedledum, while another might call tweedledum first. If they have side effects, that may be important. – Chris Dodd Jul 23 '15 at 23:33
  • Ooh -- interesting point. Is there a way to cause one to occur before the other? I assume separate statements would do it (vague understanding of [sequence points](https://en.wikipedia.org/wiki/Sequence_point), but I'm not positive. – Jason S Jul 24 '15 at 00:15
  • @JasonS You'd have to introduce a sequence point (via one of the mechanisms listed in that wikipedia article). In this case, you'd have to use separate statements, and at that point you might as well use logical operators instead of bitwise operators. – jamesdlin Jul 24 '15 at 00:26

4 Answers4

4

From section 6.3.1.2/1 of the C99 standard:

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

If you're using stdbool.h, then bool (which is a preprocessor macro defined to be _Bool) therefore must be only 0 or 1, your tweedledee and tweedledum functions cannot return values outside of that range, and using bitwise operations on them should do what you expect.

If, however, tweedledee and tweedledum are using some other bool type that isn't _Bool, then all bets are off.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • I still hope C17 (or whenever the next version will be released) adds some non-`#undef`able `#define` to the preprocessor so that any re-definition of vital macros by some ido* will eventually generate an error. – too honest for this site Jul 23 '15 at 23:45
1

To some extent, the safety of the sample that you posted will depend on the compiler/version/platform in use.

A potentially safer implementation for the use of '&' would be something like the following:

bool either_tweedle = ( tweedledee(&mystate) != 0 ) & ( tweedledum(&mystate) != 0 );

This defends against the possibility of either tweedledee or tweedledum shoving a value other than 0 or 1 into their bool return value.

The '|' case you provided should be perfectly safe.

0

I'm not sure whether a function returning bool can safely be assumed to return 1 and 0, rather than something else as an alternate value for true.

Yes. You can safely assume this and use bitwise operations.

From C99 (ISO 9899:1999) 7.16.3:

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.

Mikel Rychliski
  • 3,455
  • 5
  • 22
  • 29
  • Hmm. I'm not talking about whether `true` evaluates to 1. I'm asking whether a function that returns a `bool` can be assumed to evaluate to 1. If I write `bool nasty() { return 8; }` will 8 be cast to 1? – Jason S Jul 23 '15 at 23:19
  • 1
    I'm not sure if that's a *safely* assumption that can be made in general. It depends on the code. The only safe way is using the ugly `_Bool` keyword because C99 and C11 have the obsolescent feature allowing the three macros (`bool`, `true` and `false`) to be un- and redefined. – cremno Jul 23 '15 at 23:26
  • @cremno: If you are going in that direction, you are lost anyway. macros could even `#define int unsigned` or similar. That's what coding standards are for: to ensure such is not done (among others). – too honest for this site Jul 23 '15 at 23:42
  • @Olaf: I see your point. However `bool` is a bit more special than `int` by not being part of K&R C / C90 (people might have defined their own `bool`) and by not being a keyword. I think an answer to this question should mention this (like the current most upvoted does) even if it's unlikely. – cremno Jul 24 '15 at 00:02
  • @cremno: "people might have defined their own bool". Yes, that's why I mention coding standards. Also: if they did, you will either get a redefinition error from cpp, or a Syntax error (typedef/enum). There is a point, however, you have to rely on the code you use. – too honest for this site Jul 24 '15 at 00:16
-1

If you are using the result of the logical operation as the condition of an if-statement, it is possible that one of the both functions will not be executed at all. If this is not intended, then you'd better save the results in two variables and then do logical operation directly on the result variables.

kenny-liu
  • 309
  • 2
  • 8
  • Short circuit evaluation is not related to a conditional _statement_, but the boolean operators as OP apparently is very well aware of. That is actually the reason for his question: to avoid this. And it is very well defined by the standard. – too honest for this site Jul 23 '15 at 23:52