将指针与不同数组进行比较以获得相等性是否是未指定的行为?

时间:2011-02-05 21:26:36

标签: c++ pointers standards unspecified-behavior

相等运算符在指针上具有关系运算符的语义限制:

  

==(等于)和!=(不等于)运算符与关系运算符具有相同的语义限制,转换和结果类型,除了它们的优先级和实际值较低的结果。 [C ++03§5.10p2]

关系运算符对比较指针有限制:

  

如果相同类型的两个指针p和q指向不是同一对象的成员或相同数组的元素或不同函数的不同对象,或者如果它们中只有一个为空,则p< q,p> q,p< = q,并且p> = q未指定。 [§5.9p2]

这是一个由等式运算符“继承”的语义限制吗?

具体来说,给定:

int a[42];
int b[42];

显然(a + 3)< (b + 3)未指定,但是(a + 3)==(b + 3)也未指定?

3 个答案:

答案 0 :(得分:16)

op==op!=的语义明确表示映射是,但其真值结果除外。因此,您需要查看为其真值结果定义的内容。如果他们说结果未指定,那么它是未指定的。如果他们定义了特定的规则,那么它就不是。它特别说

  

同一类型的两个指针比较相等,当且仅当它们都为空时,都指向相同的函数,或者两者都表示相同的地址

答案 1 :(得分:11)

只要指针指向相同类型的对象,等于运算符(==!=)的结果就会产生指定的结果。给定两个指向同一类型的指针,恰好其中一个是真的:

  1. 两者都是空指针,它们相互比较相等。
  2. 都是指向同一个对象的指针,它们相互比较相同。
  3. 它们是指向不同对象的指针,它们相互比较不相等。
  4. 至少有一个未初始化,并且未定义比较结果(事实上,比较本身可能永远不会发生 - 只是尝试读取指针以进行比较会产生未定义的行为)。
  5. 在相同的约束下(两个指针都指向同一类型的对象),排序运算符(<<=>>=)的结果是仅指定它们是指向同一对象的指针,还是指定同一数组中的对象(为此目的,分配了mallocnew等的“块”内存,有资格作为数组)。如果指针引用不属于同一数组的单独对象,则结果未指定。如果一个或两个指针尚未初始化,则表明存在未定义的行为。

    尽管如此,标准库中的比较模板(std::lessstd::greaterstd::less_equalstd::greater_equal 都会产生一个有意义的结果,即使内置运算符没有。特别是,它们需要产生总排序。因此,您可以根据需要进行排序,而不是使用内置的比较运算符(当然,如果其中一个或两个指针未初始化,行为仍未定义)。

答案 2 :(得分:6)

由于在一致性语义上存在混淆,因此这些是C ++的规则。 C使用完全不同的一致性模型。

  1. 未定义的行为是一个矛盾的术语,它意味着翻译不是你的程序,可以随心所欲。这通常意味着它可以生成代码,它也可以做任何它喜欢的事情(但这是一个演绎)。如果标准表示行为未定义,则文本对用户来说实际上没有意义,因为删除此文本不会改变标准对翻译人员的要求。

  2. 错误形成的程序意味着除非另有说明,否则严格定义翻译器的行为:需要拒绝您的程序并发出诊断消息。 这里的主要特例是单一定义规则,如果您违反了您的程序格式错误但不需要诊断。

  3. 实现定义要求翻译者包含明确指定行为的文档。在这种特殊情况下,未定义的行为可能是结果,但必须明确说明。

  4. 未指定是一个愚蠢的术语,这意味着行为来自一个集合。在这个意义上,定义良好只是一种特殊情况,其中允许的行为集只包含一个元素。未指定不需要文档,因此在某种意义上它也与没有文档定义的实现相同。

  5. 通常,C ++标准不是语言标准,而是标准语言的模型。要生成实际标准,您必须插入各种参数。最容易识别的是实现定义的限制。

    标准中存在一些愚蠢的冲突,例如,合法的翻译人员可以拒绝每个看似很好的C ++程序,因为您需要提供main()函数,但翻译者只支持1个字符。 QOI 或实施质量的概念解决了这个问题。它基本上说,谁在乎,没有人会因为它符合要求而购买该编译器。

    技术上,当指针指向不相关的对象时,operator <的未指定性质可能意味着:你会得到某种结果,无论是真还是假,但你的程序不会崩溃,但这不是未指定的正确含义,因此这是一个缺陷:未指定对标准编写者施加负担以记录允许行为的集合,因为如果集合是打开的,那么它等同于未定义的行为。 / p>

    我实际上提出std::less作为问题的解决方案,一些数据结构要求密钥完全有序,但指针不是operator <完全排序的。在大多数使用线性寻址的机器上less<相同,但是对x86处理器的less操作可能更昂贵。