指针减法在C中什么时候没有定义? char*buf=malloc(bufsize) char*ptr=buf; … while(条件){ ptrdiff\u t offset=ptr-buf;//bufsize){ //我们需要更多的空间 bufsize+=128; buf=realloc(buf,bufsize); ptr=buf+offset;//buf可能位于一个全新的位置 } *ptr++=…//写入此字节 }
这是有效的还是未定义的 我本以为它是有效的,但我读到一些关于它未定义的东西,所以我用谷歌搜索了一下。这些链接似乎不可避免地声称它是未定义的:指针减法在C中什么时候没有定义? char*buf=malloc(bufsize) char*ptr=buf; … while(条件){ ptrdiff\u t offset=ptr-buf;//bufsize){ //我们需要更多的空间 bufsize+=128; buf=realloc(buf,bufsize); ptr=buf+offset;//buf可能位于一个全新的位置 } *ptr++=…//写入此字节 },c,arrays,pointers,undefined-behavior,pointer-arithmetic,c11,C,Arrays,Pointers,Undefined Behavior,Pointer Arithmetic,C11,这是有效的还是未定义的 我本以为它是有效的,但我读到一些关于它未定义的东西,所以我用谷歌搜索了一下。这些链接似乎不可避免地声称它是未定义的: 但是,在这些问题中没有提及: 这些都是关于不是两个指针在同一个“数组”中。这是否意味着堆栈上有一个普通的旧C数组 如果它未定义,对我来说似乎很奇怪……当我可以访问一个常量指针和一个移动指针时,为什么要强迫我携带一个计数器变量?指针指向由malloc返回的内存块,并将其计数为同一数组: 7.22.3内存管理功能 1-该 如果分配成功,[从
如果它未定义,对我来说似乎很奇怪……当我可以访问一个常量指针和一个移动指针时,为什么要强迫我携带一个计数器变量?指针指向由
malloc返回的内存块,并将其计数为同一数组:
7.22.3内存管理功能
1-该
如果分配成功,[从malloc
]返回的指针[…]可以分配给
指向任何类型对象[…]的指针,然后使用
访问所分配空间中的此类对象或此类对象数组(直到
显式解除分配)
ptrdiff\u t offset=ptr-buf;// 这是一种定义的行为,只要不超过数组末尾的一个元素。C99§6.5.6/8说明了添加指针和整数:
[…]如果指针和
操作数和结果指向同一数组对象的元素,或超过最后一个的元素
阵列对象的元素,评估不应产生过流;否则
行为是不确定的。[……]
以及关于减法的第9段:
9) 减去两个指针时,两个指针都应指向同一数组对象的元素,
或超过数组对象最后一个元素一次;[……]
以及§7.20.3/1:
如果分配失败,指针将返回
SUCCESS适当对齐,以便可以将其指定给指向任何类型对象的指针
然后用于访问分配空间中的此类对象或此类对象的数组
(直到空间被明确释放)
因此,一旦将ptr
移动到最后一个数组元素之后的元素之外,执行指针减法就是未定义的行为
我确实相信有一些系统会因为这段代码而表现不好,尽管我不能说出任何系统的名字。理论上,malloc()
可以返回指向可寻址内存结尾之前的指针,例如,如果请求255个字节,则在32位系统上可能返回0xFFFF00,因此在结尾之外创建指针将导致溢出。指针表示上的整数溢出也可能触发某种陷阱(例如,如果指针存储在特殊寄存器中)。虽然我不知道有任何系统具有这些属性,但C标准肯定允许它们的存在。谢谢。我不确定这是否只是使用了不同的术语,或者我只是缺少了一些东西。标准的某些部分会建议这样做,比如struct foo char arr[5][5];}*p=malloc(25)
,左值p->arr[x][y]无论x
的值是多少,都不会为范围0..4之外的y
的任何值定义code>,即使索引项位于相同的分配区域内。现在还不清楚如何才能p->arr[y]
得到一个可以索引到该区域内所有地址的指针。是的,但是“…同一数组对象的元素…”让我感到困惑。malloc’d内存块是“数组对象”吗?ecatmur在回答中引用了标准的相关段落。作为旁注,甚至定义为:inta=0;int*p=&a;int*q=&a+1;ptrdiff_t d=p-q
因此,一旦将ptr移动到最后一个数组元素之后的元素之外,执行指针减法就是未定义的行为。除非ptr
超过最后一个数组元素。理论上,malloc可以返回指向可寻址内存末尾之前的指针,例如,如果您请求256字节,它可以在32位系统上返回0xFFFF00,实际上它不能返回,因为超过最后一个数组元素规则。C标准在一个非规范性脚注中说:以这种方式来看,一个实现只需在对象结束后提供一个额外字节(可能与程序中的另一个对象重叠),以满足“超过最后一个元素一个”的要求。对不起,我错过了一次只增加一个字节的部分,请参阅更新。一次执行一个字节是可以的,但是如果您要以更大的增量跳转,并且超过一个字节,则这是未定义的行为。
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
}
ptrdiff_t offset = ptr - buf; // <========== THIS LINE