比较指向不同数组的指针是否相等是否是未指定的行为?
相等运算符具有关系运算符对指针的语义限制:
==(等于)和 !=(不等于)运算符与关系运算符具有相同的语义限制、转换和结果类型,只是它们的优先级和真值结果较低。 [C++03 §5.10p2]
关系运算符对比较指针有限制:
如果两个相同类型的指针 p 和 q 指向不同的对象,且不是同一对象的成员或同一数组的元素或指向不同的函数,或者只有其中一个为 null,则 p<< q、p>q、p<=q和p>=q是未指定的。 [§5.9p2]
这是由相等运算符“继承”的语义限制吗?
具体地,给出:
int a[42];
int b[42];
显然,(a+3)<a。 (b + 3) 未指定,但 (a + 3) == (b + 3) 也未指定吗?
The equality operators have the semantic restrictions of relational operators on pointers:
The == (equal to) and the != (not equal to) operators have the same semantic restrictions, conversions, and result type as the relational operators except for their lower precedence and truth-value result. [C++03 §5.10p2]
And the relational operators have a restriction on comparing pointers:
If two pointers p and q of the same type point to different objects that are not members of the same object or elements of the same array or to different functions, or if only one of them is null, the results of p<q, p>q, p<=q, and p>=q are unspecified. [§5.9p2]
Is this a semantic restriction which is "inherited" by equality operators?
Specifically, given:
int a[42];
int b[42];
It is clear that (a + 3) < (b + 3) is unspecified, but is (a + 3) == (b + 3) also unspecified?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
op==
和op!=
的语义明确表示映射除了它们的真值结果。因此,您需要查看其真值结果的定义。如果他们说结果是未指定的,那么它就是未指定的。如果他们定义了具体规则,那就不是了。它特别说The semantics for
op==
andop!=
explicitly say that the mapping is except for their truth-value result. So you need to look what is defined for their truth value result. If they say that the result is unspecified, then it is unspecified. If they define specific rules, then it is not. It says in particular只要指针指向相同类型的对象,相等运算符(
==
和!=
)的结果就会产生指定的结果。给定两个指向同一类型的指针,以下条件之一为真:在相同的约束下(两个指针都指向相同类型的对象)排序运算符的结果(
<
、<=
、>,
>=
) 仅当它们都是指向同一对象的指针或指向同一数组中的单独对象的指针时才指定(为此目的,分配的内存“块”malloc
、new
等符合数组的条件)。如果指针引用不属于同一数组的单独对象,则结果未指定。如果一个或两个指针尚未初始化,则会出现未定义的行为。尽管如此,标准库中的比较模板(
std::less
、std::greater
、std::less_equal
和 < code>std::greater_equal) do 都会产生有意义的结果,即使内置运算符不会产生有意义的结果。特别是,它们需要产生总排序。因此,如果需要,您可以进行排序,只是不使用内置比较运算符(当然,如果其中一个或两个指针未初始化,则行为仍然未定义)。The result from equality operators (
==
and!=
) produce specified results as long as the pointers are to objects of the same type. Given two pointers to the same type, exactly one of the following is true:Under the same constraints (both pointers are to the same type of object) the result from the ordering operators (
<
,<=
,>
,>=
) is only specified if both of them are pointers to the same object, or to separate objects in the same array (and for this purpose, a "chunk" of memory allocated withmalloc
,new
, etc., qualifies as an array). If the pointers refer to separate objects that are not part of the same array, the result is unspecified. If one or both the pointers has not be initialized, you have undefined behavior.Despite that, however, the comparison templates in the standard library (
std::less
,std::greater
,std::less_equal
andstd::greater_equal
) do all yield a meaningful result, even when/if the built-in operators do not. In particular, they are required to yield a total ordering. As such, you can get ordering if you want it, just not with the built-in comparison operators (though, of course, if either or both of the pointers is un-initialized, the behavior is still undefined).由于一致性语义存在混乱,因此这些是 C++ 的规则。 C 使用完全不同的一致性模型。
未定义的行为是一个矛盾的术语,它意味着翻译器不是你的程序,可以随心所欲地做。这通常意味着它可以生成代码,该代码也可以做任何它想做的事情(但这是一个推论)。如果标准说行为未定义,则文本实际上对用户没有任何意义,因为删除此文本不会改变标准对翻译人员提出的要求。
格式错误的程序意味着除非另有说明,否则翻译器的行为是严格定义的:需要拒绝您的程序并发出诊断消息。
这里的主要特殊情况是单一定义规则,如果您违反了您的程序格式错误但不需要诊断的情况。
定义的实现对翻译器提出了一个要求,即它包含明确指定行为的文档。在这种特殊情况下,未定义的行为可能是结果,但必须明确说明。
未指定是一个愚蠢的术语,它意味着行为来自一组。从这个意义上说,明确定义只是一种特殊情况,其中允许的行为集仅包含一个元素。未指定不需要文档,因此在某种意义上它也意味着与没有文档定义的实现相同。
一般来说,C++ 标准不是语言标准,而是语言标准的模型。要生成实际的标准,您必须插入各种参数。其中最容易识别的是实现定义的限制。
标准中存在一些愚蠢的冲突,例如,合法的翻译器可以拒绝每个看似良好的 C++ 程序,因为您需要提供
main()
函数,但翻译器只支持1 个字符的标识符。这个问题可以通过 QOI 或实施质量的概念来解决。它基本上是说,谁在乎呢,没有人会仅仅因为它符合标准就购买该编译器。从技术上讲,当指针指向不相关的对象时,
operator <
的未指定性质可能意味着:您将得到某种或真或假的结果,但您的程序不会崩溃,但是这不是未指定的正确含义,因此这是一个缺陷:未指定给标准编写者带来了记录允许行为集的负担,因为如果该集合是开放的,那么它相当于未定义的行为。我实际上提出了 std::less 来解决某些数据结构要求键是全序的,但指针不是按运算符
进行全序排序的问题。在大多数使用线性寻址的机器上,
less
与<
相同,但在 x86 处理器上进行less
操作可能会更昂贵。Since there's confusion on conformance semantics, these are the rules for C++. C uses a completely different conformance model.
Undefined behaviour is an oxymoronic term, it means the translator NOT your program, may do as it pleases. This generally means it can generate code which will also do anything it pleases (but that is a deduction). Where the Standard says behaviour is undefined the text is actually of no significance to the user in the sense that eliding this text will not change the requirements the Standard imposes on translators.
Ill formed program means that unless otherwise specified the behaviour of the translator is rigidly defined: it is required to reject your program and issue a diagnostic message.
The primary special case here is the One-Definition Rule, if you breach that your program is ill-formed but no diagnostic is required.
Implementation defined imposes a requirement on the translator that it contain documentation specifying the behaviour explicitly. In this special case Undefined Behaviour can be the result but must be explicitly stated.
Unspecified is a stupid term which means that the behaviour come from a set. In this sense well-defined is just a special case where the set of permitted behaviours contains only one element. Unspecified does not require documentation, so in some sense it also means the same as implementation defined without documentation.
In general, the C++ Standard is a not a Language Standard, it is a model for a language Standard. To generate an actual Standard you have to plug in various parameters. The easiest of these to recognize are the implementation defined limits.
There are a couple of silly conflicts in the Standard, for example, a legitimate translator can reject every apparently good C++ program on the basis that you are required to supply a
main()
function but the translator only supports identifiers of 1 character. This problem is resolve by the notion of QOI or Quality of Implementation. It basically says, who cares, no one is going to buy that compiler just because it is conforming.Technically the unspecified nature of
operator <
when the pointers are to unrelated objects is probably intended to mean: you will get some kind of result which is either true or false but your program will not crash, however this is not the correct meaning of unspecified, so that is a Defect: unspecified imposed a burden on the Standards writers to document the set of allowed behaviours because if the set is open, then it is equivalent to undefined behaviour.I actually proposed
std::less
as a solution to the problem that some data structures require keys to be totally ordered, but pointers are not totally ordered byoperator <
. On most machines using linear addressingless
is the same as<
, but theless
operation on, say, an x86 processor is potentially more expensive.