9

我一直在阅读只要您不离开数组的边界,就定义了指针算术。我不确定我是否完全理解这意味着什么,我有点担心。因此这个问题。

假设我从一个指向数组开头的指针开始:

int *p = (int*) malloc(4 * sizeof(int));

现在我创建了两个位于数组边界之外的新指针:

int *q = p + 10;
int *r = p - 2;

现在指针q-10, q-9, ..., r+2, r+3, 等等都位于数组的边界内。它们有效吗?例如,r[3] 保证p[1]给出与?相同的结果

我已经做了一些测试并且它有效。但我想知道这是否包含在通常的 C 规范中。具体来说,我使用的是 Visual Studio 2010、Windows,并且我正在使用本机 C(不是 C++)进行编程。我被覆盖了吗?

4

3 回答 3

9

您正在做的工作适用于您正在使用的实现以及最流行的实现,但它不符合 C。正如 chris 所引用的,

§6.5.6/8:如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义

它未定义的事实在未来可能会变得越来越重要,更高级的静态分析允许编译器将这种代码变成致命错误,而不会产生运行时成本。

顺便说一句,减去不在同一个数组中未定义的指针的历史原因是分段内存(想想 16 位 x86;熟悉它的人会想考虑“大”内存模型)。虽然指针可能涉及段和偏移组件,但编译器可以仅在偏移组件上执行算术以避免运行时成本。这使得不在同一段中的指针之间的算术无效,因为差异的“高部分”丢失了。

于 2012-08-24T03:51:13.370 回答
5

根据 C11 标准,§6.5.6/8(我将第一部分放在上下文中):

当一个整数类型的表达式被添加到一个指针或从一个指针中 减去
...
产生溢出;否则,行为未定义。

因此,在数组之外且没有结束的结果是未定义的行为。

于 2012-08-24T03:51:14.210 回答
-1

“是”您提到的条件已包含在规范中。

    int *r = p - 2;

r 在数组 p 的边界之外,评估结果是分配位置给 r,在 p 的地址之后/之前有 2 个 int 位置。

`r[3]` 只是 r 地址之后的“第 4 个”int 位置
于 2012-08-24T06:07:41.627 回答