指针算法是否仍在数组外工作?

bec*_*cko 9 c arrays pointers language-lawyer

我总是在读取指针算法的定义,只要你不离开数组的边界即可.我不确定我完全理解这意味着什么,我有点担心.因此这个问题.

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

int *p = (int*) malloc(4 * sizeof(int));
Run Code Online (Sandbox Code Playgroud)

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

int *q = p + 10;
int *r = p - 2;
Run Code Online (Sandbox Code Playgroud)

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

我做了一些测试,它的工作原理.但我想知道这是否适用于通常的C规范.具体来说,我使用的是Visual Studio 2010,Windows,而且我使用的是原生C(非C++)编程.我被覆盖了吗?

R..*_*R.. 9

你正在做的是你正在使用的实现,以及最流行的实现,但它不符合C.正如克里斯所引用的,

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

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

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


chr*_*ris 5

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

当一个具有整数类型的表达式被添加到指针或从指针中减去时
......
如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不得产生溢出; 否则,行为未定义.

因此,在数组之外而不是在结束之外的结果是未定义的行为.

  • 这很有趣因为定义了`p + 2 - 2`,但是'p - 2 + 2`是未定义的.关联性如此之多...... (5认同)
  • @Mysticial:的确如此.顺便说一句,这会带来一个容易犯的错误.像`ptr + index - base_index`这样的代码是错误的,如果`index`超出指向数组的边界,则调用UB.替代形式`ptr +(index - base_index)`或`&ptr [index-base_index]`通常是你需要的.我自己犯过这个错误很多次了. (4认同)
  • 不是那个确切的问题,但类似的问题导致了一个重大错误.我错误地将一个适度过大的偏移量添加到基指针以获得"结束指针",然后只要指针小于结束指针就循环.代码在32位处理器上运行原生的i386-linux(在3-4gb范围内从未发生指针)和x86_64处理器上运行良好,但在64位内核上运行的i386代码失败,因为堆栈已经放入非常接近0xffffffff并且加法溢出.结果是一次难以追查的严重崩溃. (3认同)