为了迭代数组我们应该使用size_t还是ptrdiff_t?
在这篇由Andrey Karpov撰写的题为“关于size_t
和ptrdiff_t
”的博客文章中,他展示了一个例子,
for (ptrdiff_t i = 0; i < n; i++) a[i] = 0;
但是,我不确定这是否正确,似乎应该如此
for (size_t i = 0; i < n; i++) a[i] = 0;
它是否正确?
我知道我们也应该使用类似memset
东西,但让我们完全避免这种情况。 我只问这种类型
在博客文章中 ,我认为你应该总是避免分配大于PTRDIFF_MAX
(*)的内存块,因为这样做会使得像Clang和GCC这样的编译器产生无意义的代码,即使你没有以某种方式减去指向该块的指针导致结果溢出。
(*)即使malloc
成功传递的值大于PTRDIFF_MAX
。 问题的关键在于GCC和Clang只生成与这样的malloc
链接时行为正确的代码,但Glibc提供了一个不实现此限制的malloc
函数。
如果您遵循该约束(我鼓励您:这是博客文章的消息),那么这两种类型都是同样正确的。
这就是说,由于只需要表示正偏移量,因此size_t
将是您示例中的自然选择。
使用ptrdiff_t
是可以的,因为a[i]
被翻译为*(a + i)
。
如果你拿两个指针, p1
和p2
,鼓励你使用:
ptrdiff_t d = p2 - p1; // Assuming p2 - p1 is valid.
鉴于此, p2 == p1 + d
,即
是有效表达式。 ptrdiff_t
或size_t
是否更好,因为索引类型是团队中使用的意见和/或编码样式的问题。
OP问题的答案是肯定的,size_t最适合示例代码,其中没有相互减去指针值,并且没有关于malloc
行为的交叉编译器/库兼容性问题。 无论堆管理器的区别如何,在C中,数组的长度可以是SIZE_MAX
字节,并且需要size_t
来表示它。 标准中没有任何内容要求堆管理器能够在堆中分配所有进程内存空间,或者为此分配最多SIZE_MAX
字节,但是数组的长度可以是SIZE_MAX
,因此size_t
是合适的。
即使n
被签名,使用ptrdiff_t
for i
也无济于事,因为初始i < n
测试无论如何都会失败,如果n
为负,因为i
初始化为零。 i
中没有size_t
索引无法访问的索引。 需要ptrdiff_t
的唯一地方是从另一个指针值中减去一个指针值,OP不会询问这一点。