Is the following expression undefined behavior ?

N

Neroku

I don't know if the following expression is UB:

i=2;
x = (i=3) * i;

Since in C, evaluation order is unspecified, this expression is 'at
least' unspecified, since we don't know which operand evalutes first,
(i=3) or i, So, would x be always 6 or 9 ? depending on the evaluation
order.

TIA
 
W

Walter Roberson

I don't know if the following expression is UB:
i=2;
x = (i=3) * i;
Since in C, evaluation order is unspecified, this expression is 'at
least' unspecified, since we don't know which operand evalutes first,
(i=3) or i, So, would x be always 6 or 9 ? depending on the evaluation
order.

The relevant wording in C89 (ANSI X3.159-1989) is,

Between the previous and next sequence point an object shall
have its stored value modified at most once by the evaluation of
an expression. Furthermore, the prior value shall be accessed
only to determine the value to be stored. [34]

with footnote:

[34] This paragraph renders undefined statement expressions such as
i = ++i + 1;
while allowing
i = i + 1;


This wording occurs in a main heading for the description of the
operators, and in my interpretation must be treated as equivilent
as a constraint. But we can answer the question more directly without
resorting to interpretations: notice that the footnote specifically
says that "renders undefined", so the behaviour is "undefined",
not merely "unspecified".
 
K

Kenneth Brody

Neroku said:
I don't know if the following expression is UB:

i=2;
x = (i=3) * i;

Since in C, evaluation order is unspecified, this expression is 'at
least' unspecified, since we don't know which operand evalutes first,
(i=3) or i, So, would x be always 6 or 9 ? depending on the evaluation
order.

While most implementations will probably give you one of those
values, the definition of UB means that you can't guarantee it.

Consider a platform capable of parallel operations, and the code
generated includes these two operations to be carried out in
parallel:

stor 3,i ; store 3 in i
mult 3,i,a1 ; multiply i by 3, return in register a1

This could generate a hardware fault, as &i is accessed for both
read and write at the same time.


While most UB examples include modifying an item twice between
sequence points, as in:

i = i++;
or
x = i++ + ++i;

I believe that the UB in question is really "modified, and accessed
for some purpose other than determining the value to modify" (or
similar phrasing), so the following is UB as well:

x = i++ + i;


If I'm wrong (though I don't believe that I am), I'm sure someone
will correct me shortly. :)

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
F

Flash Gordon

Neroku wrote, On 09/02/07 17:51:
I don't know if the following expression is UB:

i=2;
x = (i=3) * i;

Since in C, evaluation order is unspecified, this expression is 'at
least' unspecified, since we don't know which operand evalutes first,
(i=3) or i, So, would x be always 6 or 9 ? depending on the evaluation
order.

Evaluation order is not the problem here. The problem is that you read
"i" for a reason other than determining its new value. So it is
undefined behaviour and you could get any value or a crash or wreck the
process due to a bus clash when it tries to simultaneously read and
write "i".
 
K

Keith Thompson

I don't know if the following expression is UB:
i=2;
x = (i=3) * i;
Since in C, evaluation order is unspecified, this expression is 'at
least' unspecified, since we don't know which operand evalutes first,
(i=3) or i, So, would x be always 6 or 9 ? depending on the evaluation
order.

The relevant wording in C89 (ANSI X3.159-1989) is,

Between the previous and next sequence point an object shall
have its stored value modified at most once by the evaluation of
an expression. Furthermore, the prior value shall be accessed
only to determine the value to be stored. [34]

with footnote:

[34] This paragraph renders undefined statement expressions such as
i = ++i + 1;
while allowing
i = i + 1;


This wording occurs in a main heading for the description of the
operators, and in my interpretation must be treated as equivilent
as a constraint. But we can answer the question more directly without
resorting to interpretations: notice that the footnote specifically
says that "renders undefined", so the behaviour is "undefined",
not merely "unspecified".

No, it's not a constraint, since it's not marked as one. The standard
says:

If a "shall" or "shall not" requirement that appears outside of a
constraint is violated, the behavior is undefined.

which applies in this case.

Constraint violations must be diagnosed at compile time, which is not
possible in general for this requirement. Rather than this:
x = (i = 3) * i;
consider this:
x = (*p1 = 3) * *p2;
It's not possible to determine at compile time whether *p1 and *p2 are
the same object. If they aren't, there's nothing wrong with the
statement.
 
S

Serve Laurijssen

Keith Thompson said:
(e-mail address removed)-cnrc.gc.ca (Walter Roberson) writes:
Constraint violations must be diagnosed at compile time, which is not
possible in general for this requirement. Rather than this:
x = (i = 3) * i;
consider this:
x = (*p1 = 3) * *p2;

well in general its not possible indeed, but can the compiler give an error
when it knows for certain it's the same object?
or warning at most?
 
G

Guest

Serve said:
well in general its not possible indeed, but can the compiler give an error
when it knows for certain it's the same object?
or warning at most?

A compiler in conforming mode may not refuse to compile it, unless it
can prove that the code will always be executed. And naturally, a
compiler may additionally support non-conforming modes in which such
code does cause a hard error.
 
F

Flash Gordon

Harald van Dijk wrote, On 10/02/07 16:16:
A compiler in conforming mode may not refuse to compile it, unless it
can prove that the code will always be executed. And naturally, a
compiler may additionally support non-conforming modes in which such
code does cause a hard error.

The compiler is allowed to produce a warning for it, since compilers are
allowed to warn anything they want.
 
G

Guest

Flash said:
Harald van Dijk wrote, On 10/02/07 16:16:

The compiler is allowed to produce a warning for it, since compilers are
allowed to warn anything they want.

Right, so long as the warning does not cause the compilation to fail
in any of the compiler's modes that are meant to be conforming. (A
warning is not necessarily a non-fatal diagnostic, though admittedly
the only cases of fatal warnings in real-world compilers I've seen
were the result of compiler bugs.)
 
K

Keith Thompson

Serve Laurijssen said:
well in general its not possible indeed, but can the compiler give an error
when it knows for certain it's the same object?
or warning at most?

Of course, the compiler can give a warning for anything it likes, and
it can give a fatal error if it can prove that it will always invoke
undefined behavior (not, for example, if the statement is enclosed in
"if (0) { ... }". But since it's not a constraint violation, it's not
required to do so, even when it happens to be easy to figure it out at
compile time.
 
T

Thad Smith

Harald van Dijk wrote:
[regarding undefined behavior for x = (i = 3) * i;]
A compiler in conforming mode may not refuse to compile it, unless it
can prove that the code will always be executed. And naturally, a
compiler may additionally support non-conforming modes in which such
code does cause a hard error.

A compiler may additionally support non-conforming modes which define
the behavior for such constructs.
 
T

Thad Smith

Thad said:
Harald van Dijk wrote:
[regarding undefined behavior for x = (i = 3) * i;]
A compiler in conforming mode may not refuse to compile it, unless it
can prove that the code will always be executed. And naturally, a
compiler may additionally support non-conforming modes in which such
code does cause a hard error.

A compiler may additionally support non-conforming modes which define
the behavior for such constructs.

Or a conforming mode which defines the behavior for such constructs.
 
F

Flash Gordon

Thad Smith wrote, On 12/02/07 05:48:
Harald van Dijk wrote:
[regarding undefined behavior for x = (i = 3) * i;]
A compiler in conforming mode may not refuse to compile it, unless it
can prove that the code will always be executed. And naturally, a
compiler may additionally support non-conforming modes in which such
code does cause a hard error.

A compiler may additionally support non-conforming modes which define
the behavior for such constructs.

Defining behaviour for such constructs would not make it non-conforming.
Implementations are allowed to define what the C standard leave undefined.
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top