++i vs i++

D

Dan Pop

In said:
I'd like to point out that the expression (i-- != 1)
is semantically equal to (--i != 0), (except where i is a pointer)
meaning that any implementation might translate those two
expressions identically. I would be more likely to use the second
expression in source code, than the first.

If the comparison against 1 makes more sense (in context), I'd use
(i-- != 1). The best version in such cases is the one best reflecting
the algorithm being implemented or the programmer's intentions.

Dan
 
M

Michael Mair

Hiho,

It's all subjective to who the code's audience is. To experienced
programmers, operators like '++' become second nature. And consider:

(*p).
vs
p->

Which is more readable and which is used more often?

The second and again the second -- why?
Seriously:

Depends. I have one "favourite" line to type in when debugging
with ddd some places in the code where you can see errors coming
from other places:
graph display t->tr.n[0]->myvertex->iv.x[0]@2
displaying the first two entries of an array residing in
a structure residing in a union pointed to from a structure
pointed to from a structure residing in a union t is pointing
to. I find this nicer than
graph display ((*(*((*t).tr).n[0]).myvertex).iv).x[0]@2

I admit -> takes more time to take in intuitively but then
you see at once what is meant.


Cheers
Michael
 
M

Method Man

Derrick Coetzee said:
Keep in mind that not every programmer who maintains your code may be an
expert, or be an expert who is particular lucid at the time (under high
stress, low on sleep, hangover, etc.) To experienced programmers,
assembly language is second nature, but that doesn't mean we prefer it.


The important thing is that lexical order reflects execution order. In
this case you can read "p->" as a single conceptual operation with
chooses a member from the object p refers to. The choice of * as a
prefix rather than a postfix operator is arbitrary (although in this
case needed to automatically parse things correctly). This is
effectively a local transformation, unlike ++, which can potentially be
transmitted across an arbitrarily long string of tokens, as in this example:

b = a++ + /* one-million token expression */;
--

The example I gave was not intended to be related to pre/post fixing of
operators. The point was simply to illustrate that code can be _subjective_
to those who read it.

ProgrammerA might consider a 'for' loop easier to read than a 'while' loop,
whereas programmerB might think the opposite in the exact same code
semantics. So which way is more "boring and obvious"?

Of couse there are many other examples, but I'll return to '++'. As I said,
I personally find 'while(*++p) { ... }' easier to read than 'for(p++; *p;
p++) { ... }'. In other cases, you're right in that I would find p++ easier
to read than ++p. It just depends and my own programming experience in C/C++
has a lot to do with it.
 
D

Derrick Coetzee

Michael said:
graph display t->tr.n[0]->myvertex->iv.x[0]@2
graph display ((*(*((*t).tr).n[0]).myvertex).iv).x[0]@2

This is actually a great example of what I mean (not that I think you're
trying to contradict me, but just as an aside). In the abstract C
machine, the dereference operation *follows* the operand to which it
applies in execution order. Effectively, [0] is the postfix version of
*. In the SPECS C++ syntax (see _A Modest Proposal: C++ Resyntaxed_),
where ^ is a postfix dereference operator, the above expression would be
written like this:

t^.tr.n^^.myvertex^.iv.x^

We don't need arrows, [0], or parentheses this way, just one postfix
dereference operator. I think it's pretty neat.
 
K

Keith Thompson

Flash Gordon said:
No they aren't. In one you are comparing against the value i has BEFORE
it is decremented and in the other you are comparing against the value i
has AFTER it is decremented.

Right, but they're comparing against different values:

(i-- != 1)
(--i != 0)

so, as far as I can tell, they're equivalent (assuming that i is an
integer; due to roundoff, they can also be different if i is a
floating-point object). A sufficiently clever compiler could well
generate the same code for both. (Unless you can think of a type and
value for i for which they're different, excluding cases that invoke
undefined behavior.)
 
F

Flash Gordon

No they aren't. In one you are comparing against the value i has
BEFORE it is decremented and in the other you are comparing against
the value i has AFTER it is decremented.

Oops. I just realised you were testing against different values. Ignore
me.
 
M

Malcolm

Eric Sosman said:
Have you been smoking those funny cigarettes again, Malcolm? It's
unlike you to make such idioTmatic remarks ... I'd be interested to
know what other C operators you think "shouldn't be used," and on what
grounds, however shaky. I'm sure it'd be amusing.
The other baddy is the conditon ? x : y operator. It doesn't mean anything
to someone who doesn't know C (but is maybe a skilled programmer in another
language, and is forced to maintain your C program by circumstance), and
usually if() ... else would be clearer.
However the use in macros is legitimate, and also sometimes if many
conditions are tested then it can lead to a more intuitive code layout.

++i doesn't have such redeeming features. The form should be banned, because
where it is used for the increment alone then it is completely exchangeable
with the postfix form. Where it is used in a compound expression with the
value taken, it leads to confusion. The postfix form is useful for iterating
through arrays, whilst the prefix form is almost never so useful.

(This does lead us to the interesting issue of whether prefix --i should
also be banned. If you want to reverse through an array, generally you will
be passed the size of it, i.e. and index one past the end.)
 
J

John Bode

Hi All,

I would like to know when ++i should be used instead of i++ and vice versa.
Some code examples would be of help.

The distinction is whether you need the current value of i (i++) or
the current value of i+1 (++i) in an expression.

Consider a simple stack implemented as an array. The stack grows from
element 0. We have a variable sp that always points to the last thing
pushed onto the stack. When we push a new value onto the stack, we
write to the next available array element and update sp to point to
this new element.

if (sp < STACK_SIZE)
{
/*
** The following statement replaces these two statements
**
** sp = sp + 1;
** stack[sp] = value;
*/
stack[++sp] = value;
}
else
{
/* handle overflow */
}

Popping or removing the top item from the stack is the inverse
operation; we return the value currently pointed to by sp, then
decrement by one:

if (sp > 0)
{
/*
** The following statement replaces these two statements
**
** value = stack[sp];
** sp = sp - 1;
*/
value = stack[sp--];
}
else
{
/* stack empty */
}
Does it really matter for assignments?

Yes.

i = 0;
j = i++; /* j == 0 */

i = 0;
j = ++i; /* j == 1 */
 
M

Michael Wojcik

In C, the form i++ is idiomatic. The form ++i really shouldn't be used. It
increments i before calculating the value of i, which is almost never
required.

Yet a quick scan through the 4062 C source files on this machine found
1068 instances of pre-increment and pre-decrement operators. Perhaps
idioms are different around these parts.

Obviously pre-increment are pre-decrement are never "required"; neither
are the post- forms, or the compound assignment operators, and so on.
Whether they're useful is a different question, as is whether they're
commonly used.
Even if it would be handy, its use will confuse maintaining
programmers.

(Conditional as subjunctive ... ugh. And then indicative as conditional.
What ill moods that sentence has.)

Few of those 1068 instances were written by me, yet I find none
of them confusing.
 
S

Simon Stienen

Malcolm said:
++i doesn't have such redeeming features. The form should be banned, because
where it is used for the increment alone then it is completely exchangeable
with the postfix form. Where it is used in a compound expression with the
value taken, it leads to confusion. The postfix form is useful for iterating
through arrays, whilst the prefix form is almost never so useful.

-----BEGIN SARCASM BLOCK-----
i++ should also be banned. It leads to confusion if you are not an expert
regarding C++, just take this example:
if (i++==i++) { ... }

Both arguments of the comparison are exactly the same. Nevertheless, the
comparison will return false. THIS IS GOING TO CONFUSE BEGINNERS! STRIP
POST-INCREMENTS FROM C++!!
------END SARCASM BLOCK------
 
D

Derrick Coetzee

Method said:
ProgrammerA might consider a 'for' loop easier to read than a 'while' loop,
whereas programmerB might think the opposite in the exact same code
semantics. So which way is more "boring and obvious"?

If you prefer, here are some alternate translations:
Original:
while(*++p) { ... }
With comma:
while(p++, *p) { ... }
Duplicating increment:
p++;
while(*p) { ...; p++; }

Even better is avoiding pointer arithmetic in the first place and
sticking to array indices:

int i;
for(i=1; p; i++) { ... }

Induction variable elimination, now a commonplace optimization,
translates this into the original.
It just depends and my own programming experience in C/C++ has a lot to do with it.

I'm not saying pre/postincrement should be "banned" or that no one
should ever use them, but I do think not using them helps produce code
that most programmers can understand more easily. If I really wanted to
put force in this statement though I'd want a full usability study
behind it.
 
B

Ben Pfaff

Simon Stienen said:
-----BEGIN SARCASM BLOCK-----
i++ should also be banned. It leads to confusion if you are not an expert
regarding C++, just take this example:
if (i++==i++) { ... }

If you *are* an expert, then this code tells you that its author
is an idiot and that you should avoid using it at all costs.
 
S

Simon Stienen

Ben Pfaff said:
If you *are* an expert, then this code tells you that its author
is an idiot and that you should avoid using it at all costs.

Just needed some code to show Malcom that intuitive understandable code is
a matter of the code itself and therefore depends on the style of its
author - as soon as you have a minimum understanding on the C language...
Malcoms statement is like saying: "Since I am nearly unable to speak
French, French scientists are not allowed to use their special terms,
because I do not understand them if they do so!"
Every language, not limited to spoken languages, has terms, which somebody
who wants to learn this language has to learn, too. This is true even for
programming languages. If you don't learn your C vocabulary, obviously you
can't understand C code.

Malcom: Next time, you could demand XOR to be removed from the language
(and the microprocessors), because AND and OR are naturally unterstood
while XOR is far more complex an can be replaced with "(a OR b) AND NOT (a
AND b)" anstead of "a XOR b". :)
 
A

Arthur J. O'Dwyer

Just needed some code to show Malcom that intuitive understandable code is
a matter of the code itself and therefore depends on the style of its
author - as soon as you have a minimum understanding on the C language...

...you realize that the above snippet invokes undefined behavior and
thus can't be used to as an example in the way you suggested.
Malcoms statement is like saying: "Since I am nearly unable to speak
French, French scientists are not allowed to use their special terms,
because I do not understand them if they do so!"

To which you rejoined, "Je ne qxi pas frqustl maqnxwth!" :)

HTH,
-Arthur
 
M

Malcolm

Michael Wojcik said:
Yet a quick scan through the 4062 C source files on this machine found
1068 instances of pre-increment and pre-decrement operators. Perhaps
idioms are different around these parts.
As compared to how many post-increment / decrements?
 
S

Simon Stienen

Malcolm said:
As compared to how many post-increment / decrements?

There are more people driving a pick-up than there are people driving a
caterpillar...
Let's stop producing caterpillars and use pick-ups instead.
 
M

Malcolm

added by Malcolm

int stack[STACK_SIZE];
int sp;
if (sp < STACK_SIZE)
{
/*
** The following statement replaces these two statements
**
** sp = sp + 1;
** stack[sp] = value;
*/
stack[++sp] = value;
}
else
{
/* handle overflow */
}
Now I've added natural code given the identifiers you used. Since you only
posted a fragment, it isn't technically an error.
Your example shows UB when sp equals STACK_SIZE -1. As I said, use of
pre-increment can be confusing.
 
M

Mark F. Haigh

Derrick Coetzee said:
As a practical matter, you should almost never use either of these
except on a line by itself, in which case it doesn't matter. The
reasoning behind this claim is that it's difficult to read statements
using these operators and they can always be pulled out into a separate
statement. Here are some examples of pulling them out:

*p1++ = *p2++;
...becomes...
*p1 = *p2;
p1++; p2++;

while(*++p) { ... }
...becomes...
for(p++; *p; p++) { ... }
<snip>

I happen to disagree. This is purely a stylistic matter. It's
difficult for *you* to read, but more consise and more idiomatic in my
opinion.

We'll just have to agree to disagree.

Mark F. Haigh
(e-mail address removed)
 
J

John F. Bode

added by Malcolm

int stack[STACK_SIZE];
int sp;
if (sp < STACK_SIZE)
{
/*
** The following statement replaces these two statements
**
** sp = sp + 1;
** stack[sp] = value;
*/
stack[++sp] = value;
}
else
{
/* handle overflow */
}
Now I've added natural code given the identifiers you used. Since you only
posted a fragment, it isn't technically an error.
Your example shows UB when sp equals STACK_SIZE -1. As I said, use of
pre-increment can be confusing.

Yes, thank you, I tossed that off while waiting for a build to finish
and wasn't paying terribly close attention.
 
E

Eric Sosman

Derrick said:
If you prefer, here are some alternate translations:
Original:
while(*++p) { ... }
[...]
Duplicating increment:
p++;
while(*p) { ...; p++; }

Note that these two forms are *not* necessarily
equivalent. For extra credit: Why not?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,201
Latest member
KourtneyBe

Latest Threads

Top