C++ 为什么C++;11是否包含关于比较空指针的奇数子句?

C++ 为什么C++;11是否包含关于比较空指针的奇数子句?,c++,c++11,pointers,language-lawyer,comparison-operators,C++,C++11,Pointers,Language Lawyer,Comparison Operators,在检查另一个问题的引用时,我注意到C++11中的一个奇怪的子句,位于[expr.rel]^3: 可以比较指向void(指针转换后)的指针,结果定义如下:如果 指针表示相同的地址或都是空指针值,如果运算符为 =和false否则;否则,结果未指定 这似乎意味着,一旦将两个指针强制转换为void*,它们的顺序关系就不再得到保证;例如,这: int foo[] = {1, 2, 3, 4, 5}; void *a = &foo[0]; void *b = &foo[1]; std::co

在检查另一个问题的引用时,我注意到C++11中的一个奇怪的子句,位于[expr.rel]^3:

可以比较指向
void
(指针转换后)的指针,结果定义如下:如果 指针表示相同的地址或都是空指针值,如果运算符为
=
false
否则;否则,结果未指定

这似乎意味着,一旦将两个指针强制转换为
void*
,它们的顺序关系就不再得到保证;例如,这:

int foo[] = {1, 2, 3, 4, 5};
void *a = &foo[0];
void *b = &foo[1];
std::cout<<(a < b);
intfoo[]={1,2,3,4,5};
void*a=&foo[0];
void*b=&foo[1];

std::coutTL;医生:

  • 在C++98/03中,该子句不存在,标准也没有为
    void
    指针指定关系运算符(核心问题879,见本文末尾)
  • C++11中添加了关于比较
    void
    指针的奇怪子句来解决它,但这反过来又导致了另外两个核心问题583和1512(见下文)
  • 这些问题的解决要求删除该条款,并替换为C++14标准中的措辞,该措辞允许“正常”
    void*
    比较

核心问题583:

  • 与空指针常量部分的关系指针比较:8.9[expr.rel]
  • 在C中,这是格式错误的(参见C99 6.5.8):

    void f(char*s){
    如果(s<0){}
    }…但是在C++中,它不是。为什么?当他们可以写(s!=0)时,谁会需要写(s>0)?
    
    这是自ARM(可能更早)以来使用的语言; 显然,这是因为指针转换(7.11[conv.ptr])需要 当其中一个操作数为 指针类型。所以它看起来像“null ptr到实指针类型” 转换是和其他指针转换搭便车

    拟议决议(2013年4月):

    该问题通过第1512期的决议得以解决

    核心问题1512:

  • 指针比较与限定转换部分:8.9[expr.rel]
  • 根据8.9[expr.rel]第2段,描述指针 比较,

    指针转换(7.11[conv.ptr])和限定转换 (7.5[conv.qual])对指针操作数(或指针)执行 操作数和空指针常量,或两个空指针常量, 其中至少有一个是非整数的)以将它们带到 复合指针类型。这似乎会导致以下情况 示例格式不正确

     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.
    
    bool-foo(整数**x,常数整数**y){
    返回x
    这对于指针比较来说似乎太严格了,而且是当前的 实现接受这个例子

    拟议决议(2012年11月):


    上述问题解决方案的相关摘录见论文:

    以下内容还解决了核心问题583

    5.9 expr.rel第1至5段的变更:

    在本节中,以下语句(C++11中的奇数子句)已被删除:

    指向
    void
    (指针转换后)的指针可以进行比较,结果定义如下:如果两个指针表示相同的地址或都是空指针值,如果运算符为
    =
    false
    ,则结果为
    true
    ;否则,结果将不确定

    并且添加了以下语句:

    • 如果两个指针指向同一数组的不同元素或其子对象,则指向下标较高的元素的指针比较大
    • 如果一个指针指向数组的一个元素或其子对象,而另一个指针指向数组最后一个元素的另一个指针,则后一个指针比较大
    因此,在C++14(n4140)第[expr.rel]/3节的最终工作草案中,上述陈述与决议时的陈述相同


    通过挖掘添加这一奇怪条款的原因,我找到了一个更早的问题879:。 该问题的拟议解决方案(2009年7月)导致增加该条款,该条款于2009年10月被表决为WP


    这就是它被包含在C++ 11标准中的原因。< /P>它不是奇怪的,C和C++是类型化语言,把整数数组的地址分配给VoIP *不是一个类似的赋值,因此需要一个强制转换。静态_-cast(foo)@splaten:任何数据指针都有到

    void*
    的隐式转换,因此不需要显式转换,尽管在某些奇怪的体系结构上(想到分段内存),到
    void*
    的转换可能不是普通的位拷贝;尽管如此,我无法想象一种体系结构,其中指向“big,
    void
    pointer”的“常规指针”转换不会保留同一数组元素之间的顺序关系“计算a和b之间的元素数量;如果是阴性的话b@MSalters:我还可以想象
    a-b
    被实现为
    intc;而((c=rand())+b=a),但这并不意味着它接近合理。:-)此外,我认为它违反了算法/容器部分中规定的时间复杂性要求;bool b=(void*)和c==(void*)和c
    将是假的,这与所有理由都不符。我读对了吗?这解释了为什么它被删除了,但为什么
     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.