索引数组时我应该总是使用 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_t
在char[N]
、uint8_t[N]
、int[N]
等情况下
size_t
在std::vector
和std::list
的情况下
int
在 QList
和 QVector
的情况下
位数组的任意精度整数 (aint)(如果位数组的 size()
方法返回一个 aint)
在内存中压缩数组的情况下为 aint(如果数组的 size()
方法返回 aint)
如果数组跨越多台机器,则为 aint(如果数组的 size()
方法返回 aint)
C++ 以外的其他语言:
int
在java.util.Collection
及其子类的情况下
总而言之:安全索引类型是size()
方法返回的类型。
注意:如果size()
方法返回无符号size_t
,则有符号int
和ssize_t
不是安全索引类型。在 gcc 和 clang 的情况下,编译器标志 -Wsign-compare
(由 -Wall
启用)和 -Wconversion
可用于防止大多数情况。
【讨论】:
以上是关于索引数组时我应该总是使用 size_t 吗?的主要内容,如果未能解决你的问题,请参考以下文章
通过 size_t 索引迭代到 boost::multi_index 中的顺序位置?
prepareForSegue 传递索引 0 的值...总是