Home > Enterprise >  Please, explain to me what this if condition is doing: if (! --rank[x])
Please, explain to me what this if condition is doing: if (! --rank[x])

Time:06-17

I encountered the following problem while analyzing the cpp code.

I don't understand this if condition:

if (! --rank[x])

rank is an int array, and x is an int variable.

I don't program in C . My question is, why are variables in this if not of type bool? What is this about?

CodePudding user response:

why are there variables in this if not of type bool

Convenience. When the language was designed, it was descided that

if(variable != 0)      // same as  if(variable)

or

if(pointer != NULL)    // same as  if(pointer)

was so common that normal variables and pointers should be implicitly converted to true or false in boolean contexts. 0 and NULL became false and all the rest true.

This has saved programmers from millions of keystrokes.

CodePudding user response:

For posterity, here is the standard language governing your example. The conversion of integers — or any other arithmetic type — to bool is one of the so-called standard conversions in C .

The relevant section is 7.3. The chapter starts very generally:

7.3 Standard conversions [conv]
7.3.1 General [conv.general]
Standard conversions are implicit conversions with built-in meaning.

This means two things:

  1. The compiler performs standard conversions for you automatically.
  2. They are built in to the language (they are not a library feature, and not user defined).

Then there is a list of possible conversions. One item is

(1.2) — Zero or one conversion from the following set: [...] and boolean conversions.

Boolean conversions are later defined as

7.3.15 Boolean conversions [conv.bool]
1 A prvalue of arithmetic [...] type can be converted to a prvalue of type bool. A zero value [...] is converted to false; any other value is converted to true.

(A prvalue is simply a temporary.)

The standard also has a note:

[Note 2 : Expressions with a given type will be implicitly converted to other types in several contexts:
(2.1) — When used as operands of operators. The operator’s requirements for its operands dictate the destination type (7.6). [...]

This applies in your case: operator! is a built-in operator requiring a boolean argument.

CodePudding user response:

The meaning of if (! --rank[x]) actually combines multiple aspects.

Before answering the question (what is the overall effect) I'll explain the aspects/elements that are being combined.

Firstly, everything there are a couple of properties of expressions in C .

  • all expressions may have both an effect and a result, and the two are not necessarily the same.
  • The result of an expression allows an expression to be used as part of a larger expression (in the sense of more operations)

In your example, there is an expression using multiple operators, so it is an expression composed of multiple (sub-) expressions.

First there is the "array subscripting" operator - []. If a is an array and i is an integral value, the expression a[i] accesses the ith element of array (using zero-based indexing) and gives a result that is (practically, but over-simplifying a bit) a reference to that element.

So rank[x] obtains a reference to the xth value of an array named rank.

The pre-decrement operator has an effect of decrementing (subtracting 1 from) its operand and gives a result equal to the new value of that operand. For example, --v has the effect of subtracting 1 from v and gives a result equal to the new value of v. That may seem to be splitting hairs, but the post-decrement operator works differently - it has the effect of subtracting 1 from v and a result equal to the original value of v. So, the expression foo = --v has the same net effect as

--v;
foo = v;

whereas foo = v-- has the same net effect as

foo = v;
 --v;

Although --v and v-- have the same net effect (they both decrement v) the different result of each (new and old value of v, respectively) means that the value of foo is different from foo = --v and foo = v--.

The next part is the ! (logical negation) operator. For bool values, !false maps to true and !false maps to true. For integral values, 0 is considered to be false and all non-zero values are considered true. So, if i is an int then !i gives true if i is zero and false if i is non-zero. If a bool is converted back to an int, false gives a result of zero, and true gives a result of 1.

Now, to answer the question, we combine the parts above.

The construct

 if (!--rank[x]) something();

is equivalent to

  --rank[x];
  if (!rank[x]) something();

which, in turn, is equivalent (in net effect) to

  --rank[x];
  if (rank[x] == 0) something();

In other words, it decrements rank[x] and, if the result of decrementing is zero, the statement something() will be executed.

Generally speaking, expressing this as if (!--rank[x]) is used by some programmers because it is more concise. The down-side is, because it combines multiple effects, the expression is harder for a human to understand, therefore harder to get right.

It is also possible to combine a large number of (sub-) expressions into a larger expression, which therefore has multiple effects. While more concise, the difficulty of understanding increases substantially as the number of sub-expressions increases. Going overboard and combining a large number of sub-expressions into one is therefore inadvisable in practice - it is harder to get right, harder to debug, and harder (for anyone) to maintain.

  •  Tags:  
  • c
  • Related