Order of execution question

C

CBFalconer

Keith said:
.... snip ...

You replaced an initialization (executed on each iteration of the
loop) with an equivalent assignment (executed on each iteration
of the loop). You widened the visibility of temp, making it more
difficult to confirm that it's not used before or after the loop.

The original code was quite simply better than your replacement
(though I prefer your layout). Just what improvement did you
imagine you were offering?

Well, assume the compiler is accurate and works. Then the
reallocation and reinitialization on each pass through the loop
(ignoring possible optimization effects) requires destroying the
variable and recreating it. Admittedly this can be done by simply
rewriting it, but the system may not so do. It may reduce the
stack frame, and then increase it again on each pass! (assuming a
stack)

I don't think it is a critical decision (lacking compiler bugs),
but it does avoid a possible error. Surely you will concede that
the code with the added scope will work?
 
B

Barry Schwarz

Let's say I'm freeing a linked list like the following..


while( current != NULL )
{
name* temp = current;
current = current->next;
free( temp );
}

When
current = current->next;

executes and updates 'current'. Will the value of 'current' in the
while loop get updated at the same time or is the order undefined?

There is only one object named current. It is evaluated in three
different statements and its value is changed in one statement. Each
statement is separated from the next by a semicolon which is a
sequence point. Therefore the code for each statement is completely
executed before any code for the next statement is executed. You are
guaranteed of the following order:

The present value of current is compared to the value NULL. (You
don't know - and don't care - in which order the two comparands are
evaluated but the compare occurs only after both have been evaluated.)

If the comparison evaluates to false (the two are equal), the
loop terminates.

The present value of current is stored in the object named temp.

The present value of current is used as the address of a
structure and the member of that structure named next is evaluated.
The result of this evaluation replaces the present value of current.
(Until it is changed again, this new value of current becomes the
present value.)

free is called to process the current value of temp. (A side
effect is that the current value of temp becomes indeterminate before
control returns to your function.)

The loop repeats at the first indented paragraph above.


Remove del for email
 
K

Keith Thompson

CBFalconer said:
No, I am very lazy. Also I believe I have put up sufficient (i.e.
any) reason for the safer code. It can't hurt.

Too lazy to back up your claims, but not to lazy to make them in the
first place. A dangerous combination.

Your code is not safer in any way.
 
K

Keith Thompson

CBFalconer said:
Well, assume the compiler is accurate and works. Then the
reallocation and reinitialization on each pass through the loop
(ignoring possible optimization effects) requires destroying the
variable and recreating it. Admittedly this can be done by simply
rewriting it, but the system may not so do. It may reduce the
stack frame, and then increase it again on each pass! (assuming a
stack)

It could, but the expense would be trivial, and I've never seen a
compiler that actually does so (not that I've investigated the
generated code for every compiler I've used).

Moving a variable to an outer scope to save the expense of allocating
and deallocating it is micro-optimization at its worst.
I don't think it is a critical decision (lacking compiler bugs),
but it does avoid a possible error. Surely you will concede that
the code with the added scope will work?

That's twice you've alluded to the possibility of compiler bugs.
Proper handling of variables declared within blocks is so fundamental,
going back to BCPL if I'm not mistaken, that I'd be absolutely
astonished if any released compiler got it wrong.

I fail to see how it avoids a possible error; indeed, it introduces
the risk of new errors. Yes, your code will work (assuming that
moving the variable to a larger scope doesn't introduce some naming
conflict). But you have offered no justification for making the
change that you've advocated.

If you're unwilling to take the time to look up the language rules, I
suggest you drop this. If you want to continue the discussion, do us
all the courtesy of taking the time to make some substantive and
*correct* arguments.
 
J

Joachim Schmitz

CBFalconer said:
Well, assume the compiler is accurate and works. Then the
reallocation and reinitialization on each pass through the loop
(ignoring possible optimization effects) requires destroying the
variable and recreating it. Admittedly this can be done by simply
rewriting it, but the system may not so do. It may reduce the
stack frame, and then increase it again on each pass! (assuming a
stack)
This is the micro-optimizatiopn that frequently is criticized here.
Just leave it to the Compiler to optimize this.
The benefit (simpler code, resrcticed scope of variable) by far outweights
this.
I don't think it is a critical decision (lacking compiler bugs),
but it does avoid a possible error. Surely you will concede that
the code with the added scope will work?
A Compiler that has a bug here sghoulsd get removed from the face of the
earth ASAP.

Bye, Jojo
 
C

CBFalconer

Keith said:
Too lazy to back up your claims, but not to lazy to make them in
the first place. A dangerous combination.

Your code is not safer in any way.

Now there I'll argue. It protects against compilers that have
fouled up the reinitialization of such a statement, and only uses
constructs that must be well tested. Nothing dangerous about
that. And I see no point in searching through the standard for
something that backs or fails to back my C90 contention, especially
since I don't even have a C90 standard.

I admit I don't know of any compilers so fouled. However I could
see myself making such a mistake, so I want to protect against it.
:) This correspondence is not really progressive, since it
basically an argument over preferences.
 
B

Barry Schwarz

It has nothing to do with 'using the same memory'. The point is
that you are initializing the variable on entry to the while loop.
You want that initialization code to be executed on every pass
through the loop, not on the entry to the loop. So I recommend
saying what you mean.

Since the standard requires the initialization or occur on every
iteration (6.2.4-5), that does say exactly what is meant.
In addition using that construct requires a C99 compiler. My
method only requires a C90 compiler.

I don't have a C90 standard handy but I don't think this was a change.


Remove del for email
 
K

Keith Thompson

CBFalconer said:
Now there I'll argue. It protects against compilers that have
fouled up the reinitialization of such a statement, and only uses
constructs that must be well tested.

Proper initialization of objects declared within blocks is not some
obscure construct that a compiler writer is likely to get wrong. In
fact, the body of a function definition (the part enclosed by '{' and
'}') is syntactically nothing more than a compound statement.
Nothing dangerous about
that.

It's your attitude ("Too lazy to back up your claims, but not to lazy
to make them in the first place") that I find dangerous. (Quoting
myself, not you.)
And I see no point in searching through the standard for
something that backs or fails to back my C90 contention, especially
since I don't even have a C90 standard.

So look it up in K&R, either edition. Or check the plain-text
pre-ANSI draft at <http://flash-gordon.me.uk/ansi.c.txt>, which says:

| 3.6.2 Compound statement, or block
|
| Syntax
|
| compound-statement:
| { declaration-list<opt> statement-list<opt> }
|
| declaration-list:
| declaration
| declaration-list declaration
|
| statement-list:
| statement
| statement-list statement
|
| Semantics
|
| A compound statement (also called a block )allows a set of
| statements to be grouped into one syntactic unit, which may have its
| own set of declarations and initializations (as discussed in
| $3.1.2.4). The initializers of objects that have automatic storage
| duration are evaluated and the values are stored in the objects in the
| order their declarators appear in the translation unit.
I admit I don't know of any compilers so fouled. However I could
see myself making such a mistake, so I want to protect against it.
:)

Someone implementing a compiler presumably would bother to read the
standard, or at least K&R.
This correspondence is not really progressive, since it
basically an argument over preferences.

If you *prefer* to put all declarations in the outer block of a
function, that's ok; I'd simply disagree and move on. But you haven't
been stating it as just a preference. You've been defending it with
arguments that are quite simply factually incorrect.
 
N

Nick Keighley

C90?!!!

It's been a feature of the language from day one.

It was a feature of the language
when the primates that humans descended from,
were programming in C!

that was Algol-60 (which also allowed (invented?) block declarations).
 
N

Nick Keighley

Now there I'll argue.

Bad mistake. Just read the standard, or a draft or K&R (either
edition).
Then you will realise you are WRONG.
 It protects against compilers that have
fouled up the reinitialization of such a statement, and only uses
constructs that must be well tested.

name one complier that has this bug.
 Nothing dangerous about
that.  And I see no point in searching through the standard for
something that backs or fails to back my C90 contention, especially
since I don't even have a C90 standard.

I admit I don't know of any compilers so fouled.  However I could
see myself making such a mistake, so I want to protect against it.
:)  This correspondence is not really progressive, since it
basically an argument over preferences.

no. You basically were unaware of a basic C feature and you are
now trying to cover up the fact.

Life is so much simpler if you admit you are wrong when you are wrong.
 
N

Nick Keighley

I may be mistaken about the C90 problem.  However, you must admit
that making the initialization repeat at every loop through the
while, while not assigning further data space at the same time, is
a complication.  My simple code avoids that problem.

A common way to implement this is to allow space for the inner block
declarations when the function is entered.

func
{
int a;

{
int b;
}

{
int c
}

}

The compiler allocates (stack) spoace for a, b and c on entry to
func. Note that b and c can use the same space as they are not in
scope
at the same time.

C99's variable length arrays screw this up.



--
Nick Keighley

"ALGOL 60 was a language so far ahead of its time that it
was not only an improvement on its predecessors but also
on nearly all its successors".
--C.A.R. Hoare
 
C

CBFalconer

Nick said:
re-read you K&R (1st edition)

OK, so I was both wrong and lazy. However I think you will have to
admit that I didn't let that lead me into writing any faulty code.
 
C

CBFalconer

Nick said:
A common way to implement this is to allow space for the inner
block declarations when the function is entered.

func { /* Edited to reduce vertical space - cbf */
int a;
{
int b;
}
{
int c
}
}

The compiler allocates (stack) spoace for a, b and c on entry to
func. Note that b and c can use the same space as they are not in
scope at the same time.

What I was actually worried about is:

while (condition) {
int blah = foo;

/* code */
}

compiling to generate:

assign blah space and initialize
100:
test condition
if someflag GOTO 120
code
GOTO 100
120: deassign blah

rather than

assign blah space
100:
test condition
if someflag GOTO 120
initialize blah /* Should be here, repeating */
code
GOTO 100
120: deassign blah
 
H

Harald van Dijk

C90?!!!

It's been a feature of the language from day one.

I hadn't meant to imply declaration and initialisation of variables in
nested blocks were newly introduced in C90. I referred to C90 because it
was the last version of C before C99, nothing more. I'm pretty sure we
agree on the facts, and the only issue here is wording.
 
K

Keith Thompson

CBFalconer said:
OK, so I was both wrong and lazy. However I think you will have to
admit that I didn't let that lead me into writing any faulty code.

You might consider not telling us what we "have to admit".

No, your code was not actually faulty -- but nobody claimed that it
was. That's a straw-man argument.

Your laziness led you to make an unnecessary change to perfectly good
code, a change that introduces a slightly greater risk of errors in
future maintenance due to the wider scope of the variable. It's also
led you to continue defending your incorrect claims.

I'm not going to tell you to stop making mistakes; we all do that now
and then. But if somebody you know to be knowledgeable tells you that
you've made a mistake, *take it seriously*. Corrections can be
mistaken as well, but at least take it as a cue to *look it up*.
Think of it as creative laziness; checking the facts and promptly
admitting you're wrong (if you are) is a lot less work than a lengthy
defense of an untenable position.
 
C

christian.bau

Now there I'll argue.  It protects against compilers that have
fouled up the reinitialization of such a statement, and only uses
constructs that must be well tested.  Nothing dangerous about
that.  And I see no point in searching through the standard for
something that backs or fails to back my C90 contention, especially
since I don't even have a C90 standard.

It doesn't help against compilers that foul up use of variables that
have been declared outside a loop. Never seen a compiler that has
problems with this, but you never know. Better safe than sorry.

Seriously, you should get a few hours sleep and look at this code
again.
 

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

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top