2

I ran into a new warning message after a compiler upgrade.

warning: ordered comparison of pointer with integer zero [-Wextra]

    if (inx > 0)

As it turns out inx is a pointer. Normally I would expect to see this old code compared against 0, or NULL. This got me to thinking about signed and unsigned values, and possible risk.

A bit of research suggests:

These seem to suggest that an address (returned by malloc) can never be zero

Which took me to my old copy of the standard.

4.10 Pointer conversions

1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t.

It specifically states that two null pointers compare equal.

With that in mind, is that little piece of code undefined behavior? or is there another piece to the puzzle I am missing?

Community
  • 1
  • 1
EvilTeach
  • 28,120
  • 21
  • 85
  • 141
  • What does your compiler tell you when you do `if (inx == 0)`? – Leonardo Herrera Apr 21 '14 at 15:59
  • 1
    Part of the problem is that `0` _in source code_ represents the NULL pointer. However, the NULL pointer may not be stored _in memory_ as 0. It could be 0xFFFFFFFFFFFFFFFF or any other value. Since the _actual_ value of NULL is unspecified, so are all comparisons against it. – Mooing Duck Apr 21 '14 at 16:16

2 Answers2

5

It's not undefined behaviour, but the result is unspecified if inx is not null.

C++11 5.9/2: If two pointers p and q of the same type point to different objects that are not members of the same object or elements of the same array or to different functions, or if only one of them is null, the results of p<q, p>q, p<=q, and p>=q are unspecified.

So you can be sure that the the conditional code won't execute if inx is null - but not that it will if it's not null. The comparison should probably be inx != 0, which is well defined to be true if and only if inx is non-null.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • @BenVoigt: I copied it directly out of my copy of C++11. – Mike Seymour Apr 21 '14 at 16:05
  • n3690 and n3797 both have the wording I cited. Don't those drafts bracket C++11? – Ben Voigt Apr 21 '14 at 16:06
  • @BenVoigt: I've no idea; I'm just quoting the published standard. – Mike Seymour Apr 21 '14 at 16:07
  • 1
    @BenVoigt: both your drafts are post-C++11 according to http://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents. That wording is present in draft n3290. – Mat Apr 21 '14 at 16:09
  • @Mat: Ahh, thanks. Mike's wording is also in n3485. Well good, we've now got C++03 and C++11 (in this answer of Mike's) and C++14 all covered. – Ben Voigt Apr 21 '14 at 16:09
2

You're looking at pointer conversions, but you should be looking at pointer comparisons.

Specifically, comparisons between pointers that don't refer to (subobjects of) the same array or object.

Section 5.9, paragraphs 3 and 4, this wording is found in C++14 drafts.

Comparing pointers to objects is defined as follows:

  • If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript compares greater.
  • If one pointer points to an element of an array, or to a subobject thereof, and another pointer points one past the last element of the array, the latter pointer compares greater.
  • 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 compares greater provided the two members have the same access control (Clause 11) and provided their class is not a union.

If two operands p and q compare equal (5.10), 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.

In your case, no "pointer compares greater than" relationship is defined, and therefore the operators act according to their "otherwise" behavior, giving unspecified results. This comparison won't directly crash the program, but it could take either branch through the if, assuming that inx is non-null.

Community
  • 1
  • 1
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720