【发布时间】:2015-06-12 13:44:04
【问题描述】:
我曾经认为向指针添加整数类型(假设指针指向特定大小的数组等)总是很好定义的,无论整数类型如何。 C++11 标准说 ([expr.add]):
当一个整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于积分表达式。换句话说,如果表达式 P 指向数组对象的第 i 个元素,则表达式 (P)+N(等效于 N+(P))和 (P)-N(其中 N 的值为 n)指向分别指向数组对象的第 i + n 个和第 i - n 个元素,前提是它们存在。此外,如果表达式 P 指向数组对象的最后一个元素,则表达式 (P)+1 指向数组对象的最后一个元素,如果表达式 Q 指向数组对象的最后一个元素,则表达式 (Q)-1 指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则计算不应产生溢出;否则,行为未定义。
另一方面,最近引起我注意的是,指针的内置加法运算符是根据ptrdiff_t 定义的,这是一个有符号类型(参见 13.6/13)。这似乎暗示如果一个人使用非常大(无符号)大小的malloc(),然后尝试通过带有std::size_t 值的指针添加来到达分配空间的末尾,这可能会导致未定义的行为,因为未签名的std::size_t 将转换为ptrdiff_t,这可能是UB。
我想类似的问题会出现,例如,在std::vector 的operator[]() 中,它是根据未签名的size_type 实现的。一般来说,在我看来,这样几乎不可能充分利用平台上的可用内存。
值得注意的是,在将无符号值添加到指针时,GCC 和 Clang 都没有抱怨有符号-无符号整数转换,所有相关诊断都打开了。
我错过了什么吗?
编辑:我想澄清一下,我说的是涉及指针和整数类型(不是两个指针)的加法。
EDIT2:提出问题的等效方法可能是这样。如果ptrdiff_t 的正数范围小于size_t,此代码是否会导致第二行出现UB?
char *ptr = static_cast<char * >(std::malloc(std::numeric_limits<std::size_t>::max()));
auto end = ptr + std::numeric_limits<std::size_t>::max();
【问题讨论】:
-
那么在 13.6 中为指针定义的运算符是什么?我说的是积分+指针,而不是指针+指针。
-
好的,也许你应该澄清一下。
-
标题说“指针积分”添加,但为了清楚起见,我会编辑帖子。
-
如果委员会/Stroustroup 一开始没有为此使用无符号类型就好了。
-
@BaummitAugen:Bjarne 或 C++ 委员会在这方面的唯一部分是决定 C++ 在这一点上应该与 C 保持兼容。 C 委员会已经决定(例如)
sizeof将产生无符号类型的结果,早在 C++ 标准存在之前。