473,789 Members | 2,467 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Sub-sub-expression evaluation order

Note: For those with instant reactions, this is NOT the common "why is i
= i++ not defined?" question. Please read on.
I came across an interesting question when talking with my colleagues.
According to the standard, most operators evaluate their operands in an
unspecified order. This means that in code like this:

f() + g()

the two functions may be called in either order, and still be standards-
compliant.

Fine. Now, when the evaluation of one sub-expression begins, is there
anything in the standard that says that it must complete (ignoring side-
effects) before the other sub-expression evaluation begins? In other
words, can pieces of the sub-expressions be evaluated in an interleaving
fashion?

Take this example:

f(i++) + g(i++)

The difference from the first example is the sequence points for the
function calls.

Now, obviously since f() and g() may be called in any order, this code
is non-deterministic. My question is: can the compiler evaluate the sub-
expressions in the following order, interleaving the sub-sub-expression
evaluations?

t1 = i;
t2 = i;
i++;
i++;
f(t1);
g(t2);

Note that all side-effects were finished before the function-call
sequence points, so this doesn't violate that.

If there is nothing in the standard to prevent this, then not only is
the code "f(i++) + g(i++)" non-deterministic, but it remains as
undefined as "i++ + i++".
Here is an example where I think the above problem exists, although it's
not obvious (please ignore the obvious problems and poor design; this is
pseudo-code to illustrate a point):
const char *a(void)
{
static char *x;
if (x) free(x);
x = (char*)malloc(2 );
strcpy(x, "a");
return x;
}

printf("%s %s\n", a(), a());
The obvious problem here is that the second call to a() (in either
order) will free the pointer returned by the first call.

Here is the revised version, but I believe that the following is still
undefined:

const char *a(void) { ... same as above ... }

static list *strings; // implementation not important

const char *cache(const char *in)
{
char *out;
out = strdup(in);
add_to_list(out );
return out;
}

printf("%s %s\n", cache(a()), cache(a()));
The cache() function only exists so that calls like 'printf' can be made
- that is, they copy the argument off and return the copy (and save it
in a list to be freed later). This way, the second call to a() doesn't
affect anything by freeing the old value.

But, similar to the above, I believe that an implementation is free to
evaluate the printf call in this order:

char *t1 = a();
char *t2 = a();
char *t3 = cache(t1);
char *t4 = cache(t2);
printf("%s %s\n", t3, t4);
Is this right? Is it undefined, according to the standard?
-Frank

--
fw**********@ho tmail.com
Nov 14 '05 #1
4 2579
Frank Wallingford wrote:
...
I came across an interesting question when talking with my colleagues.
According to the standard, most operators evaluate their operands in an
unspecified order. This means that in code like this:

f() + g()

the two functions may be called in either order, and still be standards-
compliant.
That's correct.
Fine. Now, when the evaluation of one sub-expression begins, is there
anything in the standard that says that it must complete (ignoring side-
effects) before the other sub-expression evaluation begins? In other
words, can pieces of the sub-expressions be evaluated in an interleaving
fashion?
Yes. The evaluation can be implemented in any way, as long as it
produces the result that satisfies the requirements imposed by the
language specification.
Take this example:

f(i++) + g(i++)

The difference from the first example is the sequence points for the
function calls.
There are indeed sequence points at the beginning of each function's
execution. However, the standard doesn't require the evaluation of
argument subexpressions to be "tightly packed" with the execution of the
corresponding function. In other words, in this particular case the
expression might be interpreted as two consecutive 'i++' evaluations
(not separated by any sequence point) followed by calls to 'f' and 'g'.
This means that the modifications of 'i' are potentially violating the
requirements of the standard and the code produces undefined behavior.
Now, obviously since f() and g() may be called in any order, this code
is non-deterministic.
If by "non-deterministic" you mean that the code produces unspecified
result, you are wrong. The code produces undefined behavior.
My question is: can the compiler evaluate the sub-
expressions in the following order, interleaving the sub-sub-expression
evaluations?

t1 = i;
t2 = i;
i++;
i++;
f(t1);
g(t2);
Yes. That's exactly what I said above. Note though, that there wouldn't
really be any sequence points between two modifications of 'i', which
leads to UB.
Note that all side-effects were finished before the function-call
sequence points, so this doesn't violate that.
What exactly do you mean by "that" here?
If there is nothing in the standard to prevent this, then not only is
the code "f(i++) + g(i++)" non-deterministic, but it remains as
undefined as "i++ + i++".
Exactly.
Here is an example where I think the above problem exists, although it's
not obvious (please ignore the obvious problems and poor design; this is
pseudo-code to illustrate a point):

const char *a(void)
{
static char *x;
if (x) free(x);
x = (char*)malloc(2 );
strcpy(x, "a");
return x;
}

printf("%s %s\n", a(), a());

The obvious problem here is that the second call to a() (in either
order) will free the pointer returned by the first call.
That's correct. But I'd say that the nature of the problem is very
different here.
Here is the revised version, but I believe that the following is still
undefined:

const char *a(void) { ... same as above ... }

static list *strings; // implementation not important

const char *cache(const char *in)
{
char *out;
out = strdup(in);
add_to_list(out );
return out;
}

printf("%s %s\n", cache(a()), cache(a()));

The cache() function only exists so that calls like 'printf' can be made
- that is, they copy the argument off and return the copy (and save it
in a list to be freed later). This way, the second call to a() doesn't
affect anything by freeing the old value.

But, similar to the above, I believe that an implementation is free to
evaluate the printf call in this order:

char *t1 = a();
char *t2 = a();
char *t3 = cache(t1);
char *t4 = cache(t2);
printf("%s %s\n", t3, t4);

Is this right?
Yes, that's perfectly possible.
Is it undefined, according to the standard?


I don't see any problems with the last portion of code. It doesn't have
any violations present in the 'f(i++) + g(i++)' example. Why exactly do
you suspect that it is undefined?

--
Best regards,
Andrey Tarasevich
Nov 14 '05 #2
Andrey Tarasevich wrote:
Here is the revised version, but I believe that the following is still
undefined:

const char *a(void) { ... same as above ... }

static list *strings; // implementation not important

const char *cache(const char *in)
{
char *out;
out = strdup(in);
add_to_list(out );
return out;
}

printf("%s %s\n", cache(a()), cache(a()));

The cache() function only exists so that calls like 'printf' can be made
- that is, they copy the argument off and return the copy (and save it
in a list to be freed later). This way, the second call to a() doesn't
affect anything by freeing the old value.

But, similar to the above, I believe that an implementation is free to
evaluate the printf call in this order:

char *t1 = a();
char *t2 = a();
char *t3 = cache(t1);
char *t4 = cache(t2);
printf("%s %s\n", t3, t4);

Is this right?


Yes, that's perfectly possible.
Is it undefined, according to the standard?


I don't see any problems with the last portion of code. It doesn't have
any violations present in the 'f(i++) + g(i++)' example. Why exactly do
you suspect that it is undefined?


Oops... I'm sorry. I misread the code. Of course, the potential
evaluation order you suggested leads to the same problem as in the
original version of the code. If you integrate the functionality of
'cache()' into 'a()' then the problem will disappear (somehow I thought
that this has already been done)

--
Best regards,
Andrey Tarasevich
Nov 14 '05 #3
Andrey Tarasevich <an************ **@hotmail.com> wrote in
news:10******** *****@news.supe rnews.com:
Andrey Tarasevich wrote:
Here is the revised version, but I believe that the following is
still undefined:

const char *a(void) { ... same as above ... }

static list *strings; // implementation not important

const char *cache(const char *in)
{
char *out;
out = strdup(in);
add_to_list(out );
return out;
}

printf("%s %s\n", cache(a()), cache(a()));

The cache() function only exists so that calls like 'printf' can be
made - that is, they copy the argument off and return the copy (and
save it in a list to be freed later). This way, the second call to
a() doesn't affect anything by freeing the old value.

But, similar to the above, I believe that an implementation is free
to evaluate the printf call in this order:

char *t1 = a();
char *t2 = a();
char *t3 = cache(t1);
char *t4 = cache(t2);
printf("%s %s\n", t3, t4);

Is this right?
Is it undefined, according to the standard?


I don't see any problems with the last portion of code. It doesn't
have any violations present in the 'f(i++) + g(i++)' example. Why
exactly do you suspect that it is undefined?


Oops... I'm sorry. I misread the code. Of course, the potential
evaluation order you suggested leads to the same problem as in the
original version of the code. If you integrate the functionality of
'cache()' into 'a()' then the problem will disappear (somehow I
thought that this has already been done)


Right - the last example is undefined because if the implementation re-
orders the sub-expressions and calls 'a' twice before calling 'cache',
then it ends up accessing memory that has been deallocated.

Thanks for your answers.

-Frank

--
fw**********@ho tmail.com
Nov 14 '05 #4
In article <Xn************ *************** ******@69.28.18 6.158>
Frank Wallingford <fw**********@h otmail.com> wrote:
Note: For those with instant reactions, this is NOT the common "why is i
= i++ not defined?" question. Please read on.
Indeed. (It is almost a comp.std.c question, it is so well-specified :-) )

[much snippage] f(i++) + g(i++)
... then not only is
the code "f(i++) + g(i++)" non-deterministic, but it remains as
undefined as "i++ + i++".
Yes. There are sequence points before the calls to f() and g(),
after the evaluation of the various parameters, but the parameter
evaluations can be "interleave d", giving this undefinedness (I
believe -- you might check in comp.std.c to see if there is any
sort of consensus on this one).

[another example, mostly snipped]
But, similar to the above, I believe that an implementation is free to
evaluate the printf call in this order:

char *t1 = a();
char *t2 = a();
char *t3 = cache(t1);
char *t4 = cache(t2);
printf("%s %s\n", t3, t4);

Is this right? Is it undefined, according to the standard?


I believe so, yes.
--
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.
Nov 14 '05 #5

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

Similar topics

9
2511
by: John Smith | last post by:
I've been playing with splint, which returns the following warning for the code below: statlib.c: (in function log_norm_pdf) statlib.c(1054,31): Expression has undefined behavior (left operand uses errno, modified by right operand): (log(x) - mu) * (log(x) - mu) Code has unspecified behavior. Order of evaluation of function parameters or subexpressions is not defined, so if a value is used and
3
2816
by: andreas ames | last post by:
Hi all, recently I came across a line of code like the following: if seq.erase(seq.begin(), seq.end()) != seq.end() /* ... */ It made me wonder if this is just bogus or if it even can invoke undefined behaviour.
10
3326
by: nachch | last post by:
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()
15
1972
by: Jeroen | last post by:
Hi all, I've got a very specific question about the evaluation order in C++. Assume some kind of custom array class, with an overloaded subscript operator. In the following code: { my_array a, b, c; a = b + c;
32
3327
by: silpau | last post by:
hi, i am a bit confused on expression evaluation order in expressions involving unary increment.decrement operators along with binary operators. For example in the following expression x += i + j + k++;
0
9663
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9506
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
10136
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9979
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9016
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6761
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5548
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4089
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3695
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.