Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"is not required" == undefined behavior?

My question is mainly about terminology and how to interpret the standard.

[expr.rel]#4:

The result of comparing unequal pointers to objects is defined in terms of a partial order consistent with the following rules:

(4.1) If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript is required to compare greater.

(4.2) If two pointers point to different non-static data members of the same object, or to subobjects of such members, recursively, the pointer to the later declared member is required to compare greater provided the two members have the same access control ([class.access]), neither member is a subobject of zero size, and their class is not a union.

(4.3) Otherwise, neither pointer is required to compare greater than the other.

I am little confused as how to interpret (4.3). Does that mean that this

#include <iostream>
int main() {
    int x;
    int y;
    std::cout << (&x < &y);
    std::cout << (&x < &y);
}

is...

  • valid C++ code and the output is either 11 or 00.
  • invalid code, because it has undefined behaivour

?

In other words, I know that (4.3) does apply here, but I am not sure about the implications. When the standard says "it can be either A or B" is this the same as saying "it is undefined" ?

like image 233
463035818_is_not_a_number Avatar asked Jul 28 '20 22:07

463035818_is_not_a_number


People also ask

What is undefined behavior in C?

When we run a code, sometimes we see absurd results instead of expected output. So, in C/C++ programming, undefined behavior means when the program fails to compile, or it may execute incorrectly, either crashes or generates incorrect results, or when it may fortuitously do exactly what the programmer intended.

What happens undefined behavior?

In computer programming, undefined behavior (UB) is the result of executing a program whose behavior is prescribed to be unpredictable, in the language specification to which the computer code adheres.

Is unspecified behavior undefined behavior?

Unspecified behavior is different from undefined behavior. The latter is typically a result of an erroneous program construct or data, and no requirements are placed on the translation or execution of such constructs.

Is there undefined behavior in Python?

Python has undefined behavior because it's implementations are written in languages that do.


3 Answers

The wording has changed in various editions of the C++ standard, and in the recent draft cited in the question. (See my comments on the question for the gory details.)

C++11 says:

Other pointer comparisons are unspecified.

C++17 says:

Otherwise, neither pointer compares greater than the other.

The latest draft, cited in the question, says:

Otherwise, neither pointer is required to compare greater than the other.

That change was made in response to an issue saying ""compares greater" term is needlessly confusing".

If you look at the surrounding context in the draft standard, it's clear that in the remaining cases the result is unspecified. Quoting from [expr.rel] (text in italics is my summary):

The result of comparing unequal pointers to objects is defined in terms of a partial order consistent with the following rules:

  • [pointers to elements of the same array]

  • [pointers to members of the same object]

  • [remaining cases] Otherwise, neither pointer is required to compare greater than the other.

If two operands p and q compare equal, p<=q and p>=q both yield true and p<q and p>q both yield false. Otherwise, if a pointer p compares greater than a pointer q, p>=q, p>q, q<=p, and q<p all yield true and p<=q, p<q, q>=p, and q>p all yield false. Otherwise, the result of each of the operators is unspecified.

So the result of the < operator in such cases is unspecified, but it does not have undefined behavior. It can be either true or false, but I don't believe it's required to be consistent. The program's output could be any of 00, 01, 10, or 11.

like image 178
Keith Thompson Avatar answered Oct 18 '22 22:10

Keith Thompson


For the provided code, this case applies:

(4.3) Otherwise, neither pointer is required to compare greater than the other.

There is no mention of UB, and so a strict reading of "neither is required" suggests that the result of the comparison could be different every time it's evaluated.

This means the program could validly output any of the following results:

00
01
10
11
like image 33
cigien Avatar answered Oct 18 '22 20:10

cigien


valid C++ code

Yes.

Nowhere does the standard say that this is UB or ill-formed, and neither is this case lacking a rule describing the behaviour because the quoted 4.3 applies.

and the output is either 11 or 00

I'm not sure that 10 or 01 are technically guaranteed to not be output 1.

Given that neither pointer is required to compare greater than the other, the result of the comparison can be either true of false. There appears to not be an explicit requirement for the result to be the same for each invocation on same operands in this case.

1 But I consider this unlikely in practice. I also think that leaving such possibility open is not intentional. Rather, the intention is to allow for deterministic, but not necessarily total order.


P.S.

auto comp = std::less<>;

std::cout << comp(&x, &y);
std::cout << comp(&x, &y);

would be guaranteed to be either 11 or 00 because std::less (like its friends) is guaranteed to impose a strict total order for pointers.

like image 4
eerorika Avatar answered Oct 18 '22 21:10

eerorika