Invariant Logical Expressions


A constant expression is defined in the ISO:C standards as an expression which can be evaluated during program translation rather than at runtime, and accordingly may be used in any place that a constant may be. Any expression which requires the evaluation of an object is not a constant expression - even if that object is of known value and is 'const' qualified.

The concept of an invariant expression is a little different. An expression is described as invariant if its value can be shown to be either 'always true' (i.e. non-zero) or 'always false' (i.e. zero). An invariant expression may contain variables and is therefore not necessarily a constant expression but it will only be described as invariant if it is being used in a Boolean sense, i.e. because it is either:

The expression 'n < 0' in the following code always evaluates to 'false' (because n is unsigned) and it is therefore an invariant expression, but not a constant expression.

    extern void foo(unsigned int n)
    {
      if (n < 0)
      {
        ...
      }
    }

The expression 'n < 10' in the following example always evaluates to 'true' because it is located within a control structure, "if (n < 5)", which constrains the value of n. It is therefore an invariant expression, but not a constant expression.

    extern void foo(unsigned int n)
    {
      if (n < 5)
      {
        if (n < 10)
        {
          ...
        }
      }
    }

The controlling expression 'i < 10' in the following example always evaluates to 'false' and is therefore an invariant expression.

    extern void foo(void)
    {
      unsigned int i;

      for (i = 20; i < 10; ++i)
      {
        ...
      }
    }

Invariant expressions are almost always unintentional and therefore symptomatic of some sort of mistake in either coding or design. The expression itself is essentially redundant (because it could be replaced by '0' or '1') but the wider consequences are generally 'dead code', 'infeasible paths' or 'infinite loops'.

Index