D and expression evaluation order.

James Dennett jdennett at acm.org
Fri Apr 27 05:20:45 PDT 2007


Bruno Medeiros wrote:
> Frits van Bommel wrote:
>> Bruno Medeiros wrote:
>>> Frits van Bommel wrote:
>>>> Bruno Medeiros wrote:
>>>>> As we know, in C/C++ there are a lot of cases where the order of
>>>>> evaluation of an expression is undefined.
>>>>>
>>>>>   i = i++;
>>>>>   c = a + (a = b);
>>>>>   func(++i, ++i);
>>>>>
>>>>> D goes one step further by defining that any such behavior is illegal:
>>>>> "Unless otherwise specified, the implementation is free to evaluate
>>>>> the
>>>>> components of an expression in any order. It is an error to depend on
>>>>> order of evaluation when it is not specified." in
>>>>> http://www.digitalmars.com/d/expression.html .
>>>>
>>>> Actually, if I read that right it just says that the order of
>>>> evaluation is undefined and should not be relied upon. Just like C/C++.
>>>
>>> Read the paragraph ahead in the doc. In D that is considered a
>>> language(i.e. compile) error and so the compiler can issue an error.
>>> In C/C++ it is merely undefined program behavior, the code remains
>>> compilable.
>>
>> IIRC[1] the C++ standard includes "causes a compile error" as one of
>> the possible consequences of undefined behavior. I'm not sure about C.
>>
>>
>> [1] I've been staying away from C++ since I started using D, so this
>> is by no means a given...
>>
> 
> I haven't read about C++ in detail, only C. But in both cases (and
> sometimes here in the NG too) I often see the documents call "undefined
> behavior" to thing they should call errors. They refer to these concepts
> almost interchangeably, whereas they are not. They overlap a lot but
> they are not the same, there is a subtle difference.

The difference is huge, not subtle.  Using undefined
behavior (unless you're writing non-portable code and
your implementation offers an extension that defines
it) is *always* an error of a serious kind.  Many
errors require diagnostics from a C or C++ compiler;
UB does not place *any* requirement on a compiler,
which is allowed to fail to translate the code, to
issue error messages, or to generate code that does
*anything*.

> Dereferencing a trash pointer, for example, *is* an error. It *causes*
> undefined behavior, but it *is not* merely undefined behavior: it *can
> crash* your program.

Undefined behavior, formally, always has that potential.
(In fact, it might be reasonable to say that the only
ways to "crash" a C or C++ program are through the use
of undefined behavior, and it is certainly correct to
say that a crash is always a permitted consequence of
using undefined behavior.)

> On the other hand if do 
>   func(i++, i++);
> where func simply prints prints its arguments, I will have undefined
> program behavior, but no program error : that code *can not ever* crash
> the program. (altough it is still likely a *conceptual* error)

It can crash your program, or cause it to fail to compile.
It's undefined behavior.  Undefined behavior, unless
specifically allowed by your implementation, means that
all bets are off.  Optimizers can assume that you won't
violate the sequence point rules, and can do unbounded
things with that information (for example).

> This is a minor nitpick, since in practice both should be equally
> avoided, but that subtle difference is still there.

Misunderstandings of what undefined behavior means are
common, but I'm not sure that your message clarifies.

(In C++ the order of evaluation is unspecified, not
undefined; this can mean that some code fragments have
UB because they violate rules on sequence points.  This
uses the terms as per the ISO C++ standard.)

-- James



More information about the Digitalmars-d mailing list