什么时候指针减法在C中未定义?

char *buf = malloc(bufsize) char *ptr = buf; … while(condition) { ptrdiff_t offset = ptr - buf; //  bufsize) { // we need more room bufsize += 128; buf = realloc(buf, bufsize); ptr = buf + offset; // buf might be in a completely new location } *ptr++ = … // write this byte } 

这是有效还是未定义

我会认为它是有效的,但我读到了一些关于它未定义的东西,所以我用Google搜索了它。 这些链接似乎不可避免地声称它未定义:

  • 安全编码
  • 减去不指向同一数组的不同元素的指针是否在C中有效?

但是,在这些SO问题中没有提到它:

  • 指针减法混淆
  • size_t返回指针减法
  • C中的指针算法

这些都谈论不是两个指针在同一个“数组”中。 这实际上是指堆栈上的普通旧C数组吗?

如果它是未定义的,对我来说似乎很奇怪…当我有权访问一个常量指针和一个移动指针时,为什么强迫我携带一个计数器变量?

指向malloc返回的malloc块的指针计为同一个数组:

C11

7.22.3内存管理function

1 – 如果分配成功,[ malloc ]返回的指针可以被分配给指向任何类型对象的指针,然后用于访问这样的对象或这些对象的数组。分配的空间(直到空间被明确释放)。

 ptrdiff_t offset = ptr - buf; // <========== THIS LINE 

这是完美定义的行为。

(C99,6.5.6p9)“当减去两个指针时,两个指针都指向同一个数组对象的元素[...]”

它是定义的行为,只要你没有超过数组末尾的一个元素。 C99§6.5.6/ 8说明了添加指针和整数:

[…]如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为是未定的。 […]

关于减法的第9段:

9)当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; […]

从§7.20.3/ 1开始:

如果分配成功,则返回指针,以便可以将其指定给指向任何类型对象的指针,然后用于在分配的空间中访问此类对象或此类对象的数组(直到空间被明确释放) 。

因此,一旦将ptr移动到最后一个数组元素之后的元素之外,执行指针减法就是未定义的行为。

我相信有些系统会因为这个代码而表现不佳,尽管我不能说出任何名称。 理论上, malloc()可以在可寻址内存结束之前返回一个指针,例如,如果你要求255个字节,它可以在32位系统上返回0xFFFFFF00,因此在末尾之外创建指针将导致溢出。 指针表示中的整数溢出也可能触发某种陷阱(例如,如果指针存储在特殊寄存器中)。 虽然我不知道任何具有这些属性的系统,但C标准肯定允许它们存在。