C 对于迭代数组,我们应该使用size\u t还是ptrdiff\u t?

C 对于迭代数组,我们应该使用size\u t还是ptrdiff\u t?,c,pointers,size-t,errata,ptrdiff-t,C,Pointers,Size T,Errata,Ptrdiff T,他举了一个例子 for (ptrdiff_t i = 0; i < n; i++) a[i] = 0; (ptrdiff_t i=0;i”,但是这个问题是C,而不是C++(猜测是C++)。链接文章完全是伪造的,充满错误和误解。你当然是对的。忘了那篇文章和写这篇文章的人吧。在这个特殊的例子中,i的所有值都是>=0,所以大小肯定更合适。这是一个有趣的皱纹,我一直很幸运地没有注意到。我从来没有被要求构建一个只需要一次分配就可以达到大小范围一半的应用程序。我确信它们确实存在,但我认为它们是罕

他举了一个例子

for (ptrdiff_t i = 0; i < n; i++)
  a[i] = 0;
(ptrdiff_t i=0;i a[i]=0; 然而,我不确定这是否正确,似乎应该如此

for (size_t i = 0; i < n; i++)
  a[i] = 0;
(大小i=0;i a[i]=0; 这是正确的吗

我知道我们可能也应该使用类似于
memset
的东西,但让我们完全避免这种情况。我只是询问中的类型,我认为您应该始终避免分配大于
PTRDIFF_MAX
(*)的内存块,因为这样做会使编译器(如Clang和GCC)生成无意义的代码,即使您没有以导致结果溢出的方式减去指向该块的指针

(*)即使
malloc
在传递大于
PTRDIFF_MAX
的值时成功。问题的关键在于,GCC和Clang仅在与此类
malloc
链接时生成行为正确的代码,但Glibc提供了一个
malloc
函数,该函数未实现此限制

如果你遵循这个约束(我鼓励你这么做:这就是博客文章的信息),那么这两种类型都是同样正确的


也就是说,由于只需要表示正偏移量,
size\u t
将是您的示例中的自然选择。

使用
ptrdiff\u t
是可以的,因为
a[i]
被翻译为
*(a+i)

如果您使用两个指针,
p1
p2
,建议您使用:

ptrdiff_t d = p2 - p1; // Assuming p2 - p1 is valid.

假定,
p2==p1+d
,即
+ptrdiff\u t
是一个有效的表达式。无论是
ptrdiff\u t
还是
size\u t
都更好,因为索引类型是一个意见问题和/或团队中使用的编码风格。

OP问题的答案是肯定的,size\u t最适合于示例代码,其中没有指针值相互减去,而且在
malloc
行为方面不存在跨编译器/库兼容性问题。不管堆管理器的不同,在C语言中,数组的长度可以是
SIZE\u MAX
字节,这需要
SIZE\u t
来表示它。标准中的任何内容都不要求堆管理器能够分配堆中的所有进程内存空间,或者为此最多分配
SIZE\u MAX
字节,但数组的长度可以是
SIZE\u MAX
,因此
SIZE\u t
是合适的


即使对
n
进行了签名,对
i
使用
ptrdiff\t
也无济于事,因为初始
i
测试无论如何都会失败,如果
n
为负,因为
i
被初始化为零。
i
中没有
size\u t
索引无法访问的索引。唯一需要
ptrdiff\u t
的地方是从另一个指针值中减去一个指针值的地方,OP不会问这个问题。

ptrdiff\u t
是有符号类型,因此如果使用访问数组,可能不太安全。这取决于
n
是什么以及
a
是什么。如果<代码> A/COD>是内置数组, SiZeSt更合适。不确定什么是“代码>容器::SiZeHype类型< /C>”,但是这个问题是C,而不是C++(猜测是C++)。链接文章完全是伪造的,充满错误和误解。你当然是对的。忘了那篇文章和写这篇文章的人吧。在这个特殊的例子中,
i
的所有值都是>=0,所以大小肯定更合适。这是一个有趣的皱纹,我一直很幸运地没有注意到。我从来没有被要求构建一个只需要一次分配就可以达到大小范围一半的应用程序。我确信它们确实存在,但我认为它们是罕见的。@jwdonahue:也许你会感兴趣-一篇来自谷歌的帖子,关于数组是如何变得足够大以至于索引算法真的溢出和崩溃的。
PTRDIFF\u MAX
不是任何对象允许的最大大小,而是a
PTRDIFF\u t
的最大值。正如
SIZE\u MAX
只是
SIZE\u t
可以表示的最大值一样。无与最大分配大小相关。这将由静态/自动对象的实现和动态分配对象的stdlib(或环境提供的任何机制,如果有的话)来保证。但是,
size\u t
保证保存允许的最大数组索引和最大可能对象的大小(以字节为单位)
ptrdiff_t
事实上并非如此(另请参见6.5.6p9)。@Olaf承认glibc允许在32位平台上分配超过2Gb的数据,这与编译器的假设以及不更改的决定相矛盾:@Olaf您读过博客文章或错误报告了吗?它们表明GCC和Clang为已定义的程序生成错误的代码。bug报告包含一个讨论,涉及GCC维护人员和libc维护人员,讨论编译器和libc之间应该解决什么问题。你的话没有给讨论增添任何内容。我认为这个证据不可靠。同时呈现类型和变量会让人感到困惑。问题是关于类型:当然是
==-
所以
+=
。但在我们的例子中,类型是有界的。例如,在上面的示例中,从
ptrdiff\u t=uintpttr\u t-uintptpttr\u t
开始。但这并不能保证有效,即使在同一个物体上也不行
ptrdiff\u t+uintpttr\u t=uintptpr\u t
也不太可能起作用。关于值而不是类型的问题,如果任何构造都有效,那么其他构造也可能有效(afaik),那么您是对的,但是在这个问题中,我们正在创建内存访问器
我的论点是,因为
i
可以是两种类型(在这个问题中,
size\u t
ptrdiff\u t
ptrdiff\u t
可以大于
size\u t
,并且是负值)