索引数组时我应该总是使用 size_t 吗?

Posted

技术标签:

【中文标题】索引数组时我应该总是使用 size_t 吗?【英文标题】:Should I always use size_t when indexing arrays? 【发布时间】:2019-04-10 02:49:25 【问题描述】:

我是否需要在索引数组时始终使用size_t,即使数组的大小不足以超过 int 的大小?

这不是我应该何时使用size_t 的问题。我只想知道,例如,一个程序是否有 2GB 的可用内存(所有这些字段都可以用 int32 索引)但是这个内存是(虚拟内存)分配给计算机的 14GB - 16GB 的“字段”内存。

在这种情况下,如果我使用int32 而不是size_t(或unsigned long int),索引内存时是否总是会失败?

也许问题更多是关于虚拟内存而不是指针。

【问题讨论】:

索引数组与主机的 RAM 无关。鼓励size_t 的原因是因为它使您的程序具有可移植性。 通常程序不需要关心它运行的机器上安装了多少内存。但如果程序逻辑规定元素数量有一个下限,那么您可以使用较小的索引类型。 size_t 保证能够索引您扔给它的任何内容的每个字节。有时很方便。 您可以使用任何大到足以容纳数组索引的整数类型。 char 适用于小型阵列。它与可寻址内存或虚拟内存的总量无关。 size_t 能够保存任何数组的任何索引,因此如果您不知道预先的大小,它会很有用。 @user4581301:C 标准不提供这样的保证。 【参考方案1】:

size_t 是一个无符号整数,能够容纳您可以分配的最大对象的大小。它对于索引很有用,因为这意味着它可以索引到您可以分配的最大数组。

这并不意味着它是索引所必需的,甚至是必要的。您可以使用任何足够大的整数类型来索引数组。 int_fast32_t 可能更快,uint_least16_t 在结构中可能更小,等等。了解您的数据,您就可以做出不错的选择。

您应该考虑的一个问题是,在某些平台上,使用有符号索引可能需要额外的符号扩展指令。例如,这里是 x86:

// movzx eax, BYTE PTR [rcx+rdx]
// ret
char get_index(char *ptr, unsigned idx)

   return ptr[idx];


// ; sign extending idx from 32 bits to 64 bits with movsx here.
// movsx rdx, edx     
// movzx eax, BYTE PTR [rcx+rdx]
// ret
char get_index(char *ptr, int idx)

   return ptr[idx];

虚拟内存超出了 C 或 C++ 的范围。从他们的角度来看,您只需对内存进行索引,并由您的平台来使其工作。实际上,您的应用程序仅使用虚拟地址;您的 CPU/OS 正在将虚拟地址转换为幕后的物理地址。这不是您需要担心的事情。

【讨论】:

【参考方案2】:

为避免程序失败,程序员应始终使用至少与size() 方法返回的类型一样大的索引类型。这确保了索引永远不会溢出数组的任何可能大小。数组的实现通常是确保其运行时大小永远不会溢出size() 方法返回的类型。这意味着索引类型应该是:

size_tchar[N]uint8_t[N]int[N] 等情况下 size_tstd::vectorstd::list 的情况下 intQListQVector 的情况下 位数组的任意精度整数 (aint)(如果位数组的 size() 方法返回一个 aint) 在内存中压缩数组的情况下为 aint(如果数组的 size() 方法返回 aint) 如果数组跨越多台机器,则为 aint(如果数组的 size() 方法返回 aint) C++ 以外的其他语言: intjava.util.Collection 及其子类的情况下

总而言之:安全索引类型是size() 方法返回的类型。

注意:如果size() 方法返回无符号size_t,则有符号intssize_t 不是安全索引类型。在 gcc 和 clang 的情况下,编译器标志 -Wsign-compare(由 -Wall 启用)和 -Wconversion 可用于防止大多数情况。

【讨论】:

以上是关于索引数组时我应该总是使用 size_t 吗?的主要内容,如果未能解决你的问题,请参考以下文章

Liquibase:diff 总是生成索引

我应该使用整数主 ID 吗?

通过 size_t 索引迭代到 boost::multi_index 中的顺序位置?

prepareForSegue 传递索引 0 的值...总是

使用 Mongo:我们应该为每种类型的大容量查询创建一个定制的索引吗?

非聚集索引会减慢插入速度吗?