While checking the references for another question, I noticed an odd clause in C++11, at [expr.rel] ¶3:
Pointers to
void
(after pointer conversions) can be compared, with a result defined as follows: If both pointers represent the same address or are both the null pointer value, the result istrue
if the operator is<=
or>=
andfalse
otherwise; otherwise the result is unspecified.
This seems to mean that, once two pointers have been casted to void *
, their ordering relation is no longer guaranteed; for example, this:
int foo[] = {1, 2, 3, 4, 5}; void *a = &foo[0]; void *b = &foo[1]; std::cout<<(a < b);
would seem to be unspecified.
Interestingly, this clause wasn't there in C++03 and disappeared in C++14, so if we take the example above and apply the C++14 wording to it, I'd say that ¶3.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 compares greater.
would apply, as a
and b
point to elements of the same array, even though they have been casted to void *
. Notice that the wording of ¶3.1 was there pretty much the same in C++11, but seemed to be overridden by the void *
clause.
Am I right in my understanding? What was the point of that oddball clause added in C++11 and immediately removed? Or maybe it's still there, but moved to/implied by some other part of the standard?
@jl987: It is not possible to compare values pointed by void * pointers without expilcitly telling the compiler how to compare them. The compiler does not know it. Only you know how to do that. In the simplest case you will have to tell the compiler what types these values have by specifying the exact type in the cast.
The void pointer in C is a pointer that is not associated with any data types. It points to some data location in the storage. This means that it points to the address of variables. It is also called the general purpose pointer.
Since void is an incomplete type, it is not an object type. Therefore it is not a valid operand to an addition operation. Therefore you cannot perform pointer arithmetic on a void pointer.
You can legally compare a void pointer with any other pointer using the “==” and “!=
TL;DR:
void
pointers (core issue 879, see end of this post);void
pointers was added in C++11 to resolve it, but this in turn gave rise to two other core issues 583 & 1512 (see below);void *
comparison.Core Issue 583: Relational pointer comparisons against the null pointer constant
- Relational pointer comparisons against the null pointer constant Section: 8.9 [expr.rel]
In C, this is ill-formed (cf C99 6.5.8):
void f(char* s) { if (s < 0) { } } ...but in C++, it's not. Why? Who would ever need to write (s > 0) when they could just as well write (s != 0)?
This has been in the language since the ARM (and possibly earlier); apparently it's because the pointer conversions (7.11 [conv.ptr]) need to be performed on both operands whenever one of the operands is of pointer type. So it looks like the "null-ptr-to-real-pointer-type" conversion is hitching a ride with the other pointer conversions.
Proposed resolution (April, 2013):
This issue is resolved by the resolution of issue 1512.
Core Issue 1512: Pointer comparison vs qualification conversions
- Pointer comparison vs qualification conversions Section: 8.9 [expr.rel]
According to 8.9 [expr.rel] paragraph 2, describing pointer comparisons,
Pointer conversions (7.11 [conv.ptr]) and qualification conversions (7.5 [conv.qual]) are performed on pointer operands (or on a pointer operand and a null pointer constant, or on two null pointer constants, at least one of which is non-integral) to bring them to their composite pointer type. This would appear to make the following example ill-formed,
bool foo(int** x, const int** y) { return x < y; // valid ? } because int** cannot be converted to const int**, according to the rules of 7.5 [conv.qual] paragraph 4.
This seems too strict for pointer comparison, and current implementations accept the example.
Proposed resolution (November, 2012):
Relevant excerpts from resolution of the above issues are found in the paper: Pointer comparison vs qualification conversions (revision 3).
The following also resolves core issue 583.
Change in 5.9 expr.rel paragraphs 1 to 5:
In this section the following statement (the odd clause in C++11) has been expunged:
Pointers to
void
(after pointer conversions) can be compared, with a result defined as follows: If both pointers represent the same address or are both the null pointer value, the result istrue
if the operator is<=
or>=
andfalse
otherwise; otherwise the result is unspecified
And the following statements have been added:
- 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.
So in the final working draft of C++14 (n4140) section [expr.rel]/3, the above statements are found as they were stated at the time of the resolution.
Digging for the reason why this odd clause was added led me to a much earlier issue 879: Missing built-in comparison operators for pointer types. The proposed resolution of this issue (in July, 2009) led to the addition of this clause which was voted into WP in October, 2009.
And that is how it came to be included in the C++11 standard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With