相等运算符在指针上具有关系运算符的语义限制:
==(等于)和!=(不等于)运算符与关系运算符具有相同的语义限制,转换和结果类型,除了它们的优先级和实际值较低的结果。 [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)也未指定?
答案 0 :(得分:16)
op==
和op!=
的语义明确表示映射是,但其真值结果除外。因此,您需要查看为其真值结果定义的内容。如果他们说结果未指定,那么它是未指定的。如果他们定义了特定的规则,那么它就不是。它特别说
同一类型的两个指针比较相等,当且仅当它们都为空时,都指向相同的函数,或者两者都表示相同的地址
答案 1 :(得分:11)
只要指针指向相同类型的对象,等于运算符(==
和!=
)的结果就会产生指定的结果。给定两个指向同一类型的指针,恰好其中一个是真的:
在相同的约束下(两个指针都指向同一类型的对象),排序运算符(<
,<=
,>
,>=
)的结果是仅指定它们是指向同一对象的指针,还是指定同一数组中的对象(为此目的,分配了malloc
,new
等的“块”内存,有资格作为数组)。如果指针引用不属于同一数组的单独对象,则结果未指定。如果一个或两个指针尚未初始化,则表明存在未定义的行为。
尽管如此,标准库中的比较模板(std::less
,std::greater
,std::less_equal
和std::greater_equal
) 都会产生一个有意义的结果,即使内置运算符没有。特别是,它们需要产生总排序。因此,您可以根据需要进行排序,而不是使用内置的比较运算符(当然,如果其中一个或两个指针未初始化,行为仍未定义)。
答案 2 :(得分:6)
由于在一致性语义上存在混淆,因此这些是C ++的规则。 C使用完全不同的一致性模型。
未定义的行为是一个矛盾的术语,它意味着翻译不是你的程序,可以随心所欲。这通常意味着它可以生成代码,它也可以做任何它喜欢的事情(但这是一个演绎)。如果标准表示行为未定义,则文本对用户来说实际上没有意义,因为删除此文本不会改变标准对翻译人员的要求。
错误形成的程序意味着除非另有说明,否则严格定义翻译器的行为:需要拒绝您的程序并发出诊断消息。 这里的主要特例是单一定义规则,如果您违反了您的程序格式错误但不需要诊断。
实现定义要求翻译者包含明确指定行为的文档。在这种特殊情况下,未定义的行为可能是结果,但必须明确说明。
未指定是一个愚蠢的术语,这意味着行为来自一个集合。在这个意义上,定义良好只是一种特殊情况,其中允许的行为集只包含一个元素。未指定不需要文档,因此在某种意义上它也与没有文档定义的实现相同。
通常,C ++标准不是语言标准,而是标准语言的模型。要生成实际标准,您必须插入各种参数。最容易识别的是实现定义的限制。
标准中存在一些愚蠢的冲突,例如,合法的翻译人员可以拒绝每个看似很好的C ++程序,因为您需要提供main()
函数,但翻译者只支持1个字符。 QOI 或实施质量的概念解决了这个问题。它基本上说,谁在乎,没有人会因为它符合要求而购买该编译器。
技术上,当指针指向不相关的对象时,operator <
的未指定性质可能意味着:你会得到某种结果,无论是真还是假,但你的程序不会崩溃,但这不是未指定的正确含义,因此这是一个缺陷:未指定对标准编写者施加负担以记录允许行为的集合,因为如果集合是打开的,那么它等同于未定义的行为。 / p>
我实际上提出std::less
作为问题的解决方案,一些数据结构要求密钥完全有序,但指针不是operator <
完全排序的。在大多数使用线性寻址的机器上less
与<
相同,但是对x86处理器的less
操作可能更昂贵。