473,395 Members | 2,689 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Evaluation order of assignment statement

Does the C specification define the order of evaluation of assignment
statements?

For example, what should be the output from the following:

int foo1() { printf("foo1\n"); return 0; }
int foo2() { printf("foo2\n"); return 0; }
int foo3() { printf("foo3\n"); return 0; }

int main()
{
int array[1];
array[foo1()] = foo2() + foo3();
}

I'm asking this question since I'm getting conflicting results on
different compilers, and want to understand whether this is a compiler
bug or not.

gcc prints: foo1, foo2, foo3.
Microsoft Visual C prints: foo2, foo3, foo1.

Thanks.

Oct 23 '06 #1
10 3279
na****@gmail.com wrote:
Does the C specification define the order of evaluation of assignment
statements?

For example, what should be the output from the following:

int foo1() { printf("foo1\n"); return 0; }
int foo2() { printf("foo2\n"); return 0; }
int foo3() { printf("foo3\n"); return 0; }

int main()
{
int array[1];
array[foo1()] = foo2() + foo3();
It's because the order of execution of the functions foo2(),
foo3() or foo1() is undefined. There's nothing wrong with
the compilers.

There no way to tell which function of the three is gonna
get called first.
}

I'm asking this question since I'm getting conflicting results on
different compilers, and want to understand whether this is a compiler
bug or not.

gcc prints: foo1, foo2, foo3.
Microsoft Visual C prints: foo2, foo3, foo1.
John
--
John Smith
Oct 23 '06 #2
In article <11**********************@e3g2000cwe.googlegroups. com>,
<na****@gmail.comwrote:
>Does the C specification define the order of evaluation of assignment
statements?
>For example, what should be the output from the following:
>int foo1() { printf("foo1\n"); return 0; }
int foo2() { printf("foo2\n"); return 0; }
int foo3() { printf("foo3\n"); return 0; }
>int main()
{
int array[1];
array[foo1()] = foo2() + foo3();
}
That isn't really a question about the order of evaluation of
assignment statements: it's really a question about the order of
evaluation of the components of an expression.

For the most part, the answer is NO.

The full answer involves complex rules about "sequence points", and
there are continual arguments about what the rules mean in obscure
circumstances. Even seasoned pros don't always agree (at least
for the first dozen flames) about the implications of sequence points
in some unusual expressions.
--
"It is important to remember that when it comes to law, computers
never make copies, only human beings make copies. Computers are given
commands, not permission. Only people can be given permission."
-- Brad Templeton
Oct 23 '06 #3
na****@gmail.com wrote:
Does the C specification define the order of evaluation of assignment
statements?
No. The rest follows.

--
Best regards,
Andrey Tarasevich
Oct 23 '06 #4
Thank you all, I just wanted to make sure it really was not defined in
any specification (that's what I originally thought).

This came up since I saw a weird bug, where a function on the RHS of an
assignment had side effects that incremented a variable used as a
subscript index on the LHS...

--
Nachch

Oct 23 '06 #5
In article <11**********************@e3g2000cwe.googlegroups. com>,
<na****@gmail.comwrote:
>Thank you all, I just wanted to make sure it really was not defined in
any specification (that's what I originally thought).
You should include enough context so that oeople can follow the
discussion without having to try to locate previous postings.

Your question was about the order of evaluation, especially for
assignment statements.

>This came up since I saw a weird bug, where a function on the RHS of an
assignment had side effects that incremented a variable used as a
subscript index on the LHS...
If I recall correctly, that situation is well defined. Each function call
has a sequence point surrounding it -- it is the order of those sequence
points relative to those of other function calls is not defined. But because
there is a sequence point for the function call, any side effects
of the function call are considered to be finalized before evaluation
of the left hand side (if my brain hasn't frotzed this up yet again.)

Of course, well-defined code is not necessarily even close to
"readable and maintainable" code!. I'd want to have very good reasons
before coding anything like that myself!
--
I was very young in those days, but I was also rather dim.
-- Christopher Priest
Oct 23 '06 #6
Walter Roberson wrote:
In article <11**********************@e3g2000cwe.googlegroups. com>,
<na****@gmail.comwrote:
Thank you all, I just wanted to make sure it really was not defined in
any specification (that's what I originally thought).

You should include enough context so that oeople can follow the
discussion without having to try to locate previous postings.

Your question was about the order of evaluation, especially for
assignment statements.

This came up since I saw a weird bug, where a function on the RHS of an
assignment had side effects that incremented a variable used as a
subscript index on the LHS...

If I recall correctly, that situation is well defined. Each function call
has a sequence point surrounding it -- it is the order of those sequence
points relative to those of other function calls is not defined. But because
there is a sequence point for the function call, any side effects
of the function call are considered to be finalized before evaluation
of the left hand side (if my brain hasn't frotzed this up yet again.)

Of course, well-defined code is not necessarily even close to
"readable and maintainable" code!. I'd want to have very good reasons
before coding anything like that myself!
--
I was very young in those days, but I was also rather dim.
-- Christopher Priest
[Sorry about the lost context, I'm using the Google client, so I just
see a posting thread]

Anyway, regarding this specific issue: I'm getting different results
with different compilers.
In my original post I used function calls that printed some output
because that was what I used to help me visualize the timeline of
execution.

My problem is actually more like this:

int g_index = 0; // global

int bar() { g_index++; return 17; }

int foo()
{
int array[10];
array[g_index] = bar();
}

Using gcc, I get 17 written in array[0].
Using Microsoft Visual C compiler, I get 17 written in array[1].

So, gcc must have evaluated the LHS first into a memory position, then
evaluated the RHS, and finally made the assignment.
MSVC on the other hand evaluated RHS first.

Is *this* thing defined in the C specification? (*this* as opposed to
the order of function evaluation, which I understand is not defined).

Thank you!
--
Nachch

Oct 23 '06 #7

na****@gmail.com wrote:
[Sorry about the lost context, I'm using the Google client, so I just
see a posting thread]

Right, but not everyone else is.

Anyway, regarding this specific issue: I'm getting different results
with different compilers.
In my original post I used function calls that printed some output
because that was what I used to help me visualize the timeline of
execution.

My problem is actually more like this:

int g_index = 0; // global

int bar() { g_index++; return 17; }

int foo()
{
int array[10];
array[g_index] = bar();
}

Using gcc, I get 17 written in array[0].
Using Microsoft Visual C compiler, I get 17 written in array[1].

So, gcc must have evaluated the LHS first into a memory position, then
evaluated the RHS, and finally made the assignment.
MSVC on the other hand evaluated RHS first.

Is *this* thing defined in the C specification? (*this* as opposed to
the order of function evaluation, which I understand is not defined).

Short answer: no. There is no sequence point separating the evaluation
of the array subscript expressing and the function call, so there's
no defined order.

In a slightly more complex case, "array[bar2()] = bar();" you could see
either bar or bar2 get called first, but it is guaranteed that the one
that gets called first is fully complete, and all side effects
evaluated, before the second is called (or any of its parameters
evaluated - although there aren't any in this example).

In your example, you probably want to do something like:

t = bar();
array[g_index] = t;

or:

t = g_index;
array[t] = bar();
depending on what you actually want to happen.

Oct 23 '06 #8
In article <11**********************@m7g2000cwm.googlegroups. com>,
<na****@gmail.comwrote:
>My problem is actually more like this:
>int g_index = 0; // global
>int bar() { g_index++; return 17; }
>int foo()
{
int array[10];
array[g_index] = bar();
}
>Is *this* thing defined in the C specification? (*this* as opposed to
the order of function evaluation, which I understand is not defined).
There are subtle nuances to sequence points that I don't think I
am clear on myself. Puzzling through the C89 wording, I -think- the
above is not valid.

There is a sequence point before the actual call to bar(), which
I understand to mean that g_index would not yet have been computed
(according to the abstract semantics.) However, at -this- level
there is no sequence point between the start of the call to bar and
the end of the assignment. An object may be modified only once
between the previous sequence point and the next, and g_index is
modified only once by the call, so that part itself is okay. However,
the previous value of an object may be accessed only to determine
the value to store, and that's being violated because the
value of g_index has to be accessed inside bar() in order to determine
the new value to store -and- the value of g_index needs to be accessed
in order to determine the subscript to use. So if I understand
correctly, that is two kinds of accesses where only one is
permitted.

But if my understanding is correct, then the following would work,
and I -suspect- it won't:

int g_index = 0; /* global */
int bar() { g_index++; return 17; }
int copyarg( int inval ) { return inval; }
void foo(void) {
int array[10];
array[g_index] = copyarg( bar() );
}

The idea here being that with the extra layer of function call,
there is a sequence point before the call to copyarg() so the
sideeffects of bar() would be finalized before copyarg() was called,
and hence the implication would be that the g_index in the subscript
should get the side-effect'd value of g_index . But it doesn't sound
right that putting in an extra layer of call could make right
a side effect.
--
All is vanity. -- Ecclesiastes
Oct 23 '06 #9
>In article <11**********************@m7g2000cwm.googlegroups. com>,
<na****@gmail.comwrote:
[with vertical compression by me]
>>int g_index = 0; // global
int bar() { g_index++; return 17; }
int foo() {
int array[10];
array[g_index] = bar();
}
>>Is *this* thing defined in the C specification? (*this* as opposed to
the order of function evaluation, which I understand is not defined).
The precise answer is that it is "unspecified".

In article <eh**********@canopus.cc.umanitoba.ca>
Walter Roberson <ro******@ibd.nrc-cnrc.gc.cawrote:
>There are subtle nuances to sequence points that I don't think I
am clear on myself. Puzzling through the C89 wording, I -think- the
above is not valid.
Depends what you mean by "valid".

The sequence points that surround the call to, and return from,
function bar(), guarantee that g_index is 0 before, and 1 after,
the call to bar(). (Assuming of course that it has not been altered
before this.) In addition, we can (I believe) be sure that in the
left-hand sub-expression "array[g_index]", g_index is evaluated
either entirely before, or entirely after, the call to bar(). It
will therefore be either 0 or 1.

Unfortunately, there is nothing that says *which* will occur. This
is not even "implementation-defined". If it were, the programmer
could read the documentation that comes with the compiler, and find
out whether array[g_index] will be array[0] or array[1], and know
the answer for that particular compiler (perhaps "that compiler with
specific flags", since there might be a compiler switch to choose
one or the other). But it is "unspecified", meaning the compiler
does not even have to tell you how it chooses when to evaluate
g_index (i.e., before or after the call to bar()).

That, in turn, means the compiler can make this choice based on
the phase of the moon, the temperature of the CPU, or any other
hard-to-predict item. You can be sure of "zero or one", but not
which.

The way to force the desired order of evaluation -- whatever that
is -- is to capture g_index with a sequence point that is ordered
with respect to the function-call sequence point. For instance:

i = g_index; /* capture value before the call */
array[i] = bar(); /* index with old value */

or:

i = bar(); /* do the call */
array[g_index] = i; /* index with new value */
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Oct 23 '06 #10
In article <eh********@news3.newsguy.com>,
Chris Torek <no****@torek.netwrote:
>The sequence points that surround the call to, and return from,
function bar(), guarantee that g_index is 0 before, and 1 after,
the call to bar(). (Assuming of course that it has not been altered
before this.)
In the C89 standard, I saw the mandatory sequence point just
before the call to functions, but I could not find any mandatory
sequence points after function calls -- at least not sequence
points "at the same level" (so to speak.)

When I refer to sequence points "at the same level", I am supposing
that the sequence points are per expression (or per statement), and
there can, in essence, be "suspended" sequence points -- in
contrast to a model in which the sequence points within an
expression evaluation are all "global" sequence points in which
*all* possible finalization (all all nesting levels) must occur.

I am not certain at the moment how to distinguish the two models,
but I'll throw something out and perhaps someone will understand
the difference and know the answer:

The C89 standard indicates that if a signal or exception occurs,
that the values of objects (including auto objects with block scope)
are determined as of the previous sequence point, and that
any modification (or volatile access) that might be "in progress"
has an uncertain state as of the time of the the signal or exception.

Suppose I have a block with an auto variable X, and inside that block
there is a sequence point (so we have finalized the auto object),
then an expression that has a call to a routine. Suppose that routine
in turn has a block with an auto Y, and the routine has completed
a sequence point (so Y has been finalized), and suppose the routine
is in the middle of an expression, and that a signal or
exception occurs.

If sequence points can be "suspended", then the state of X may be
indeterminate at the time of the signal or exception, because we
are between the sequence points in the outer routine. But if
sequence points are in some sense "global", then the sequence point
in the inner routine is a a full sequence point for the purposes
of determining whether X has a determinate value or not.

??
--
All is vanity. -- Ecclesiastes
Oct 23 '06 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Bhushit Joshipura | last post by:
This post contains one question and one proposal. A. May I know why order of evaluation of arguments is not specified in C/C++? I asked a question in comp.lang.c++ for the following...
15
by: Jens.Toerring | last post by:
Hi, I have a possibly rather stupid question about the order of evaluation in a statement like this: result = foo( x ) - bar( y ); How can I make 100% sure that foo(x) is evaluated before...
77
by: berns | last post by:
Hi All, A coworker and I have been debating the 'correct' expectation of evaluation for the phrase a = b = c. Two different versions of GCC ended up compiling this as b = c; a = b and the other...
10
by: int main(void) | last post by:
Hi all, In the following program, #include<stdio.h> int main(void) { int x = 10; int y = 10;
9
by: sturlamolden | last post by:
Python allows the binding behaviour to be defined for descriptors, using the __set__ and __get__ methods. I think it would be a major advantage if this could be generalized to any object, by...
54
by: Rasjid | last post by:
Hello, I have just joined and this is my first post. I have never been able to resolve the issue of order of evaluation in C/C++ and the related issue of precedence of operators, use of...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.