C99:数组或堆分配的缓冲区是否会以UINTPTR_MAX结束?

时间:2011-07-14 23:52:13

标签: c pointers c99 intptr

我可以假设以下不变量吗?

void foo(char *buf, size_t len) {
  // "buf" points to either an array or memory allocated with malloc().
  assert((uintptr_t)(buf + len) < UINTPTR_MAX);
}

在我正在编写的解析器中,我想使用指针标记某些偏移:例如,我可能有char *end_of_submessage,其中end_of_submessage相对于我当前的缓冲区。但是如果子消息没有在当前缓冲区内结束,我想使用一个大于当前缓冲区中任何偏移量的值。所以我会这样做:

void parse(char *buf, size_t len, uintptr_t end_of_submessage) {
  // Some parsing that might increment "buf"
  // ...

  // If end_of_submessage == UINTPTR_MAX, processing will not be
  // triggered even if we have processed our entire current buffer.
  if ((uintptr_t)buf >= end_of_submessage)
    process_submsg_end();
}

但是如果malloc()返回内存ptr + len == UINTPTR_MAX或者数组具有相同的属性,那么这个方案就会被挫败。假设这种情况永远不会发生是否安全?根据标准是否安全?如果没有,在实践中是否安全?

1 个答案:

答案 0 :(得分:5)

C标准提供的唯一保证如下:

  

ISO / IEC 9899:1999(E)§7.18.1.4/ 1

     

以下类型指定带有属性的带符号整数类型   那么任何有效的void指针都可以转换为这种类型   转换回指向void的指针,结果将相等   到原始指针:

intptr_t
     

以下类型表示   无符号整数类型,其属性是指向void的任何有效指针   可以转换为这种类型,然后转换回指向void的指针,   并且结果将与原始指针进行比较:

uintptr_t
     

这些类型是可选的。

不保证这些转换整数的精确内容。特别是,给定一个char指针p(uintptr_t)(p + 1) == ((uintptr_t)p) + 1不能保证为真。

如果要标记偏移,则应使用另一个指针的ptrdiff_t偏移量,或者只需使用指针标记结束。例如:

void parse(char *buf, size_t len, char *end_of_submessage)
{
// ...
    if (buf >= end_of_submessage)
        process_submsg_end();
}

如果end_of_submessage可能位于不同的缓冲区中,您可以使用以下内容:

char *buf_start = buf;
// ...
if (buf_start <= end_of_submessage && buf >= end_of_submessage)
  process_submsg_end();