Skip to content

Boolean logic in C: logical vs bitwise operators

C has logical operators that produce 0 or 1 and bitwise operators that work on every bit, with similar spellings and different precedence. Any non-zero value is true, which makes if (x = 1) and a & b == c the two classic slips.

LogicCNote
NOT A!a~a flips every bit
A AND Ba && ba & b is bitwise
A OR Ba || ba | b is bitwise
A XOR B!a != !ba ^ b is bitwise; normalise first
A -> B!a || bNo implication operator
A <-> B!a == !bNormalise before comparing
TRUE, FALSEnon-zero, 0true/false with <stdbool.h> or C23

!a, a && b and a || b are the logical operators; they treat any non-zero operand as true and produce exactly 1 or 0. ~a, a & b, a | b and a ^ b are bitwise: 5 && 2 is 1, but 5 & 2 is 0, because the integers share no set bit. Since C99 there is _Bool (spelled bool with the header, and a keyword in C23), and converting to it normalises any non-zero value to 1; !!x does the same in older code.

Precedence is where C bites. ! binds tightest; then the arithmetic and shift operators; then the comparisons == and !=; then &, ^, | in that order; then &&; then ||. So a & b == c is a & (b == c), which is almost never what was meant, and a == 1 && b == 2 is fine only because == outranks &&. Assignment ranks lowest, so if (x = 1) assigns and tests the value 1, which is always true.

Tangibool does not export C. Translate with the table, bracket every mixed expression, and keep the engine's truth table as the test oracle. The parser rejects &, |, ^ and ~ on input precisely because a C expression that uses them would otherwise change meaning when read as logic; with &&, || and ! a C condition is usually a valid formula as it stands.

The common slip

Comparing flags with == without normalising. If one function returns 1 for true and another returns 4 (a set bit), both are true in C, but flag1 == flag2 is false. Compare !!flag1 == !!flag2, or convert to bool at the boundary.

Questions

Is a ^ b usable as logical XOR?

Only when both operands are already 0 or 1. On arbitrary integers it is bitwise, so 2 ^ 4 is 6, which is true, although both inputs were true and a logical XOR should give false. Use !a != !b.

Why does the engine reject ~?

Because ~ is bitwise complement in C and its relatives, and ~1 is -2, which is true, not false. The parser offers NOT as the repair rather than guessing which meaning you wanted.

Related

See also

Languages

Generated from the Tangibool engine, semantics tangibool-semantics/1, engine 1.0.0, build . Every table, map, simplification and verdict on these pages was computed by the Tangibool engine when the site was built, and every claim was re-checked by the same exact checker the app uses. Limits are stated where they apply. © 2026 Foreranger LTD.