ptrdiff_t的用法

Som*_*ame 5 c language-lawyer ptrdiff-t

我正在通过连续的内存块实现迭代器,并遇到了有关其一致性用法的问题。我当前的实现(假设我正在遍历chars 数组)。

typedef struct iterator{
    void *next_ptr;
    void *limit; //one past last element pointer
} iterator_t;

void *next(iterator_t *iterator_ptr){
    void *limit = iterator_ptr -> limit;
    void *next_ptr = iterator_ptr -> next_ptr;
    ptrdiff_t diff = limit - next_ptr;
    if(diff <= 0){
        return NULL;
    }
    iterator_ptr -> next_ptr = ((char *) next_ptr) + 1;
    return next_ptr;
}
Run Code Online (Sandbox Code Playgroud)

问题在于标准索赔6.5.6(p9)

当减去两个指针时,两个指针均应指向同一数组对象的元素,或者指向数组对象的最后一个元素

这是真的。我假设我要遍历的区域是一个数组。

如果结果无法在该类型的对象中表示,则该行为未定义。换句话说,如果表达式分别指向数组对象的i-th和j-th元素,则该表达式(P)-(Q)具有值,i?j只要该值适合于type对象ptrdiff_t

的限制在以下ptrdiff_t位置定义7.20.3(p2)

极限 ptrdiff_t

PTRDIFF_MIN 65535英镑

PTRDIFF_MAX +65535

不能保证用表示的所有值size_t都应用表示ptrdiff_t

因此,根据限制判断,我们最多只能一致地减去仅65535元素数组的指针?因此,在我要减去两个指针的数组的大小未知的一般情况下,这是行不通的吗?

Som*_*ude 5

来自规范(第 7.20.3 节)

其实现定义的值应等于或大于下面给出的相应值的幅度(绝对值)

[强调我的]

所以提到的值只是最小值。实施可能有更大的限制。我希望ptrdiff_t是目标平台的字长(即 64 位系统的 64 位类型)。

并注意size_t无符号整数类型,而ptrdiff_t是有符号整数类型。这意味着并非 a 的所有值size_t都可以用 a 表示ptrdiff_t


And*_*nle 3

这似乎是C标准本身的问题。

正如您所指出的,6.5.6 加法运算符第 9 段部分指出:

当两个指针相减时,两个指针都应指向同一个数组对象的元素,或者指向数组对象最后一个元素之后的一个;结果是两个数组元素的下标之差。结果的大小是实现定义的,其类型(有符号整数类型)ptrdiff_t<stddef.h>标头中定义。如果结果无法用该类型的对象表示,则行为未定义。换句话说,如果表达式PQ分别指向数组对象的第i-th 和j-th 元素,则表达式(P)-(Q)具有该值i-j ,前提是该值适合类型 的对象ptrdiff_t。...

C 标准中似乎无法保证您可以表示 中两个指针的差异ptrdiff_t

实际上,这意味着 aptrdiff_t必须大于 a size_t。Asize_t只需要以固定位数覆盖幅度。 ptrdiff_t必须涵盖大小和方向。如果sizeof( size_t ) == sizeof( ptrdiff_t ),则不能保证 6.5.6p9 中未定义的行为不会被调用。

  • 请注意,只有当可创建的最大对象的大小大于“PTRDIFF_MAX-1”时,这才会出现问题,而据我所知,任何 64 位实现都不会出现这种情况。有一些 32 位“size_t”和“ptrdiff_t”的实现允许大于 2GB 的单个对象,并且在这些实现上可能会溢出(至少对于“char*”指针减法)。 (2认同)