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:
- The compiler performs standard conversions for you automatically.
- 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 i
th 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 x
th 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.