char *buf = malloc(bufsize)
char *ptr = buf;
…
while(condition) {
ptrdiff_t offset = ptr - buf; // <========== THIS LINE
// offset will never be negative because we only ever *increase* ptr
if ((size_t)offset > 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搜索了它。这些链接似乎不可避免地声称它未定义:
然而,在这些SO问题中没有提到它:
这些都谈论不是两个指针在同一个“数组”中。这实际上是指堆栈上的普通旧C数组吗?
如果它是未定义的,对我来说似乎很奇怪...当我有权访问一个常量指针和一个移动指针时,为什么强迫我携带一个计数器变量?
答案 0 :(得分:6)
指向malloc
返回的内存块的指针计入同一个数组:
7.22.3内存管理功能
1 - 如果分配成功[...]可能被分配给[
malloc
]返回的指针 指向任何类型的对象的指针然后使用 在分配的空间中访问这样的对象或这些对象的数组(直到空间 明确解除分配。)
答案 1 :(得分:2)
ptrdiff_t offset = ptr - buf; // <========== THIS LINE
这是完全定义的行为。
(C99,6.5.6p9)“当减去两个指针时,两个指针都指向同一个数组对象的元素[...]”
答案 2 :(得分:0)
它是定义的行为,只要你没有超过数组末尾的一个元素。 C99§6.5.6/ 8说明了添加指针和整数:
[...]如果两个指针 操作数和结果指向同一个数组对象的元素,或者指向最后一个数组对象的元素 数组对象的元素,评估不得产生溢出;否则, 行为未定。 [...]
关于减法的第9段:
9)当减去两个指针时,两个指针都指向同一个数组对象的元素, 或者超过数组对象的最后一个元素; [...]
来自§7.20.3/ 1:
如果分配则返回指针 适当地对齐成功,以便可以将其指定给指向任何类型对象的指针 然后用于在分配的空间中访问此类对象或此类对象的数组 (直到空间被明确释放)。
因此,一旦将ptr
移动到指向最后一个数组元素之后的元素之外,执行指针减法就是未定义的行为。
我相信有些系统会因为这个代码而表现不佳,尽管我不能说出任何名称。理论上,malloc()
可以返回指向可寻址存储器结束之前的指针,例如,如果你要求255个字节,它可以在32位系统上返回0xFFFFFF00,因此创建一个超出末尾的指针将导致溢出。指针表示中的整数溢出也可能触发某种陷阱(例如,如果指针存储在特殊寄存器中)。虽然我不知道任何具有这些属性的系统,但C标准当然允许它们存在。