Why does C++11 contain an odd clause about comparing void pointers?












58















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 is true if the operator is
<= or >= and false 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?










share|improve this question























  • It's not odd, C and C++ are typed languages, assigning the address of an integer array to void* isn't a like for like assignment therefore a cast is required. static_cast<void*>(foo);

    – SPlatten
    Jan 25 at 9:23






  • 3





    @SPlatten: any data pointer has an implicit conversion to void *, so no explicit cast is required, although it's true that on some odd architectures (segmented memory comes to mind) casting to void * may not be a plain bitwise copy; still, I cannot imagine an architecture where the "regular pointer" to "big, void pointer" conversion wouldn't preserve the ordering relation between elements of the same array.

    – Matteo Italia
    Jan 25 at 9:28













  • I could image pointer comparison being implemented as "count the number of elements between a and b; if it's negative then b<a". That won't work for void* of course, as there's no void.

    – MSalters
    Jan 25 at 9:47






  • 3





    @MSalters: I can also imagine a - b being implemented as int c; while((c = rand()) + b == a);, but that doesn't mean it's anywhere near sensible. :-) Also, I'd expect it to violate the time complexity requirements stated somewhere in the algorithms/containers section.

    – Matteo Italia
    Jan 25 at 9:52













  • According to the wording of that clause char c; bool b = (void *)&c == (void *)&c would be false, against all reason. Am I reading it correctly?

    – Peter A. Schneider
    Jan 25 at 14:13


















58















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 is true if the operator is
<= or >= and false 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?










share|improve this question























  • It's not odd, C and C++ are typed languages, assigning the address of an integer array to void* isn't a like for like assignment therefore a cast is required. static_cast<void*>(foo);

    – SPlatten
    Jan 25 at 9:23






  • 3





    @SPlatten: any data pointer has an implicit conversion to void *, so no explicit cast is required, although it's true that on some odd architectures (segmented memory comes to mind) casting to void * may not be a plain bitwise copy; still, I cannot imagine an architecture where the "regular pointer" to "big, void pointer" conversion wouldn't preserve the ordering relation between elements of the same array.

    – Matteo Italia
    Jan 25 at 9:28













  • I could image pointer comparison being implemented as "count the number of elements between a and b; if it's negative then b<a". That won't work for void* of course, as there's no void.

    – MSalters
    Jan 25 at 9:47






  • 3





    @MSalters: I can also imagine a - b being implemented as int c; while((c = rand()) + b == a);, but that doesn't mean it's anywhere near sensible. :-) Also, I'd expect it to violate the time complexity requirements stated somewhere in the algorithms/containers section.

    – Matteo Italia
    Jan 25 at 9:52













  • According to the wording of that clause char c; bool b = (void *)&c == (void *)&c would be false, against all reason. Am I reading it correctly?

    – Peter A. Schneider
    Jan 25 at 14:13
















58












58








58


5






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 is true if the operator is
<= or >= and false 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?










share|improve this question














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 is true if the operator is
<= or >= and false 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?







c++ c++11 pointers language-lawyer comparison-operators






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 25 at 9:20









Matteo ItaliaMatteo Italia

102k15148248




102k15148248













  • It's not odd, C and C++ are typed languages, assigning the address of an integer array to void* isn't a like for like assignment therefore a cast is required. static_cast<void*>(foo);

    – SPlatten
    Jan 25 at 9:23






  • 3





    @SPlatten: any data pointer has an implicit conversion to void *, so no explicit cast is required, although it's true that on some odd architectures (segmented memory comes to mind) casting to void * may not be a plain bitwise copy; still, I cannot imagine an architecture where the "regular pointer" to "big, void pointer" conversion wouldn't preserve the ordering relation between elements of the same array.

    – Matteo Italia
    Jan 25 at 9:28













  • I could image pointer comparison being implemented as "count the number of elements between a and b; if it's negative then b<a". That won't work for void* of course, as there's no void.

    – MSalters
    Jan 25 at 9:47






  • 3





    @MSalters: I can also imagine a - b being implemented as int c; while((c = rand()) + b == a);, but that doesn't mean it's anywhere near sensible. :-) Also, I'd expect it to violate the time complexity requirements stated somewhere in the algorithms/containers section.

    – Matteo Italia
    Jan 25 at 9:52













  • According to the wording of that clause char c; bool b = (void *)&c == (void *)&c would be false, against all reason. Am I reading it correctly?

    – Peter A. Schneider
    Jan 25 at 14:13





















  • It's not odd, C and C++ are typed languages, assigning the address of an integer array to void* isn't a like for like assignment therefore a cast is required. static_cast<void*>(foo);

    – SPlatten
    Jan 25 at 9:23






  • 3





    @SPlatten: any data pointer has an implicit conversion to void *, so no explicit cast is required, although it's true that on some odd architectures (segmented memory comes to mind) casting to void * may not be a plain bitwise copy; still, I cannot imagine an architecture where the "regular pointer" to "big, void pointer" conversion wouldn't preserve the ordering relation between elements of the same array.

    – Matteo Italia
    Jan 25 at 9:28













  • I could image pointer comparison being implemented as "count the number of elements between a and b; if it's negative then b<a". That won't work for void* of course, as there's no void.

    – MSalters
    Jan 25 at 9:47






  • 3





    @MSalters: I can also imagine a - b being implemented as int c; while((c = rand()) + b == a);, but that doesn't mean it's anywhere near sensible. :-) Also, I'd expect it to violate the time complexity requirements stated somewhere in the algorithms/containers section.

    – Matteo Italia
    Jan 25 at 9:52













  • According to the wording of that clause char c; bool b = (void *)&c == (void *)&c would be false, against all reason. Am I reading it correctly?

    – Peter A. Schneider
    Jan 25 at 14:13



















It's not odd, C and C++ are typed languages, assigning the address of an integer array to void* isn't a like for like assignment therefore a cast is required. static_cast<void*>(foo);

– SPlatten
Jan 25 at 9:23





It's not odd, C and C++ are typed languages, assigning the address of an integer array to void* isn't a like for like assignment therefore a cast is required. static_cast<void*>(foo);

– SPlatten
Jan 25 at 9:23




3




3





@SPlatten: any data pointer has an implicit conversion to void *, so no explicit cast is required, although it's true that on some odd architectures (segmented memory comes to mind) casting to void * may not be a plain bitwise copy; still, I cannot imagine an architecture where the "regular pointer" to "big, void pointer" conversion wouldn't preserve the ordering relation between elements of the same array.

– Matteo Italia
Jan 25 at 9:28







@SPlatten: any data pointer has an implicit conversion to void *, so no explicit cast is required, although it's true that on some odd architectures (segmented memory comes to mind) casting to void * may not be a plain bitwise copy; still, I cannot imagine an architecture where the "regular pointer" to "big, void pointer" conversion wouldn't preserve the ordering relation between elements of the same array.

– Matteo Italia
Jan 25 at 9:28















I could image pointer comparison being implemented as "count the number of elements between a and b; if it's negative then b<a". That won't work for void* of course, as there's no void.

– MSalters
Jan 25 at 9:47





I could image pointer comparison being implemented as "count the number of elements between a and b; if it's negative then b<a". That won't work for void* of course, as there's no void.

– MSalters
Jan 25 at 9:47




3




3





@MSalters: I can also imagine a - b being implemented as int c; while((c = rand()) + b == a);, but that doesn't mean it's anywhere near sensible. :-) Also, I'd expect it to violate the time complexity requirements stated somewhere in the algorithms/containers section.

– Matteo Italia
Jan 25 at 9:52







@MSalters: I can also imagine a - b being implemented as int c; while((c = rand()) + b == a);, but that doesn't mean it's anywhere near sensible. :-) Also, I'd expect it to violate the time complexity requirements stated somewhere in the algorithms/containers section.

– Matteo Italia
Jan 25 at 9:52















According to the wording of that clause char c; bool b = (void *)&c == (void *)&c would be false, against all reason. Am I reading it correctly?

– Peter A. Schneider
Jan 25 at 14:13







According to the wording of that clause char c; bool b = (void *)&c == (void *)&c would be false, against all reason. Am I reading it correctly?

– Peter A. Schneider
Jan 25 at 14:13














1 Answer
1






active

oldest

votes


















35














TL;DR:




  • in C++98/03 the clause was not present, and the standard did not specify relational operators for void pointers (core issue 879, see end of this post);

  • the odd clause about comparing 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);

  • the resolution of these issues required the clause to be removed and be replaced with the wording found in C++14 standard, which allows for "normal" void * comparison.




Core Issue 583: Relational pointer comparisons against the null pointer constant





  1. 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





  1. 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 is true if the operator is <= or >= and false 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.






share|improve this answer





















  • 3





    This explains why it was removed, but why was it added in first place? What was the committee trying to achieve by restricting the comparison of void *? Or I am mistaken and the example in my question results in unspecified behavior on current-day C++ (IOW they just changed the wording)?

    – Matteo Italia
    Jan 25 at 13:44






  • 1





    @MatteoItalia: I tried to hunt for the reason why it was added by looking up the "Compatibility with C++03" section in the C++11 standard but could not find anything related mentioned. Current day C++(17) also does not mention this clause in any form (as far as I could check the standard), so the behavior may just be unspecified.

    – P.W
    Jan 25 at 13:56






  • 2





    The "oddball clause" was unrelated to either core issue. It's more of a drive-by fix as the issue resolution rewrote the subclause.

    – T.C.
    Jan 25 at 18:16











  • @MatteoItalia: Please see edit to the answer which answers the question why this odd clause was added in the first place.

    – P.W
    Jan 28 at 5:20






  • 1





    @MatteoItalia: The flow looks more structured now. Thanks for the edit.

    – P.W
    Jan 30 at 4:58











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54362209%2fwhy-does-c11-contain-an-odd-clause-about-comparing-void-pointers%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









35














TL;DR:




  • in C++98/03 the clause was not present, and the standard did not specify relational operators for void pointers (core issue 879, see end of this post);

  • the odd clause about comparing 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);

  • the resolution of these issues required the clause to be removed and be replaced with the wording found in C++14 standard, which allows for "normal" void * comparison.




Core Issue 583: Relational pointer comparisons against the null pointer constant





  1. 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





  1. 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 is true if the operator is <= or >= and false 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.






share|improve this answer





















  • 3





    This explains why it was removed, but why was it added in first place? What was the committee trying to achieve by restricting the comparison of void *? Or I am mistaken and the example in my question results in unspecified behavior on current-day C++ (IOW they just changed the wording)?

    – Matteo Italia
    Jan 25 at 13:44






  • 1





    @MatteoItalia: I tried to hunt for the reason why it was added by looking up the "Compatibility with C++03" section in the C++11 standard but could not find anything related mentioned. Current day C++(17) also does not mention this clause in any form (as far as I could check the standard), so the behavior may just be unspecified.

    – P.W
    Jan 25 at 13:56






  • 2





    The "oddball clause" was unrelated to either core issue. It's more of a drive-by fix as the issue resolution rewrote the subclause.

    – T.C.
    Jan 25 at 18:16











  • @MatteoItalia: Please see edit to the answer which answers the question why this odd clause was added in the first place.

    – P.W
    Jan 28 at 5:20






  • 1





    @MatteoItalia: The flow looks more structured now. Thanks for the edit.

    – P.W
    Jan 30 at 4:58
















35














TL;DR:




  • in C++98/03 the clause was not present, and the standard did not specify relational operators for void pointers (core issue 879, see end of this post);

  • the odd clause about comparing 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);

  • the resolution of these issues required the clause to be removed and be replaced with the wording found in C++14 standard, which allows for "normal" void * comparison.




Core Issue 583: Relational pointer comparisons against the null pointer constant





  1. 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





  1. 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 is true if the operator is <= or >= and false 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.






share|improve this answer





















  • 3





    This explains why it was removed, but why was it added in first place? What was the committee trying to achieve by restricting the comparison of void *? Or I am mistaken and the example in my question results in unspecified behavior on current-day C++ (IOW they just changed the wording)?

    – Matteo Italia
    Jan 25 at 13:44






  • 1





    @MatteoItalia: I tried to hunt for the reason why it was added by looking up the "Compatibility with C++03" section in the C++11 standard but could not find anything related mentioned. Current day C++(17) also does not mention this clause in any form (as far as I could check the standard), so the behavior may just be unspecified.

    – P.W
    Jan 25 at 13:56






  • 2





    The "oddball clause" was unrelated to either core issue. It's more of a drive-by fix as the issue resolution rewrote the subclause.

    – T.C.
    Jan 25 at 18:16











  • @MatteoItalia: Please see edit to the answer which answers the question why this odd clause was added in the first place.

    – P.W
    Jan 28 at 5:20






  • 1





    @MatteoItalia: The flow looks more structured now. Thanks for the edit.

    – P.W
    Jan 30 at 4:58














35












35








35







TL;DR:




  • in C++98/03 the clause was not present, and the standard did not specify relational operators for void pointers (core issue 879, see end of this post);

  • the odd clause about comparing 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);

  • the resolution of these issues required the clause to be removed and be replaced with the wording found in C++14 standard, which allows for "normal" void * comparison.




Core Issue 583: Relational pointer comparisons against the null pointer constant





  1. 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





  1. 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 is true if the operator is <= or >= and false 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.






share|improve this answer















TL;DR:




  • in C++98/03 the clause was not present, and the standard did not specify relational operators for void pointers (core issue 879, see end of this post);

  • the odd clause about comparing 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);

  • the resolution of these issues required the clause to be removed and be replaced with the wording found in C++14 standard, which allows for "normal" void * comparison.




Core Issue 583: Relational pointer comparisons against the null pointer constant





  1. 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





  1. 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 is true if the operator is <= or >= and false 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.







share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 29 at 21:44









Matteo Italia

102k15148248




102k15148248










answered Jan 25 at 9:47









P.WP.W

16.2k31455




16.2k31455








  • 3





    This explains why it was removed, but why was it added in first place? What was the committee trying to achieve by restricting the comparison of void *? Or I am mistaken and the example in my question results in unspecified behavior on current-day C++ (IOW they just changed the wording)?

    – Matteo Italia
    Jan 25 at 13:44






  • 1





    @MatteoItalia: I tried to hunt for the reason why it was added by looking up the "Compatibility with C++03" section in the C++11 standard but could not find anything related mentioned. Current day C++(17) also does not mention this clause in any form (as far as I could check the standard), so the behavior may just be unspecified.

    – P.W
    Jan 25 at 13:56






  • 2





    The "oddball clause" was unrelated to either core issue. It's more of a drive-by fix as the issue resolution rewrote the subclause.

    – T.C.
    Jan 25 at 18:16











  • @MatteoItalia: Please see edit to the answer which answers the question why this odd clause was added in the first place.

    – P.W
    Jan 28 at 5:20






  • 1





    @MatteoItalia: The flow looks more structured now. Thanks for the edit.

    – P.W
    Jan 30 at 4:58














  • 3





    This explains why it was removed, but why was it added in first place? What was the committee trying to achieve by restricting the comparison of void *? Or I am mistaken and the example in my question results in unspecified behavior on current-day C++ (IOW they just changed the wording)?

    – Matteo Italia
    Jan 25 at 13:44






  • 1





    @MatteoItalia: I tried to hunt for the reason why it was added by looking up the "Compatibility with C++03" section in the C++11 standard but could not find anything related mentioned. Current day C++(17) also does not mention this clause in any form (as far as I could check the standard), so the behavior may just be unspecified.

    – P.W
    Jan 25 at 13:56






  • 2





    The "oddball clause" was unrelated to either core issue. It's more of a drive-by fix as the issue resolution rewrote the subclause.

    – T.C.
    Jan 25 at 18:16











  • @MatteoItalia: Please see edit to the answer which answers the question why this odd clause was added in the first place.

    – P.W
    Jan 28 at 5:20






  • 1





    @MatteoItalia: The flow looks more structured now. Thanks for the edit.

    – P.W
    Jan 30 at 4:58








3




3





This explains why it was removed, but why was it added in first place? What was the committee trying to achieve by restricting the comparison of void *? Or I am mistaken and the example in my question results in unspecified behavior on current-day C++ (IOW they just changed the wording)?

– Matteo Italia
Jan 25 at 13:44





This explains why it was removed, but why was it added in first place? What was the committee trying to achieve by restricting the comparison of void *? Or I am mistaken and the example in my question results in unspecified behavior on current-day C++ (IOW they just changed the wording)?

– Matteo Italia
Jan 25 at 13:44




1




1





@MatteoItalia: I tried to hunt for the reason why it was added by looking up the "Compatibility with C++03" section in the C++11 standard but could not find anything related mentioned. Current day C++(17) also does not mention this clause in any form (as far as I could check the standard), so the behavior may just be unspecified.

– P.W
Jan 25 at 13:56





@MatteoItalia: I tried to hunt for the reason why it was added by looking up the "Compatibility with C++03" section in the C++11 standard but could not find anything related mentioned. Current day C++(17) also does not mention this clause in any form (as far as I could check the standard), so the behavior may just be unspecified.

– P.W
Jan 25 at 13:56




2




2





The "oddball clause" was unrelated to either core issue. It's more of a drive-by fix as the issue resolution rewrote the subclause.

– T.C.
Jan 25 at 18:16





The "oddball clause" was unrelated to either core issue. It's more of a drive-by fix as the issue resolution rewrote the subclause.

– T.C.
Jan 25 at 18:16













@MatteoItalia: Please see edit to the answer which answers the question why this odd clause was added in the first place.

– P.W
Jan 28 at 5:20





@MatteoItalia: Please see edit to the answer which answers the question why this odd clause was added in the first place.

– P.W
Jan 28 at 5:20




1




1





@MatteoItalia: The flow looks more structured now. Thanks for the edit.

– P.W
Jan 30 at 4:58





@MatteoItalia: The flow looks more structured now. Thanks for the edit.

– P.W
Jan 30 at 4:58




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54362209%2fwhy-does-c11-contain-an-odd-clause-about-comparing-void-pointers%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Mario Kart Wii

What does “Dominus providebit” mean?

Antonio Litta Visconti Arese