3

这是凭记忆的,所以我可能会误用几个词,但意思应该可以理解

我目前在大学,主修编程 - 我们开始使用 C++,当我们开始使用数组时,我们的 C++ 老师(一个有奇怪想法和编程规则的老师,比如不允许任何评论)告诉我们应该使我们的数组大小为 4 的倍数,以提高效率:

char exampleArrayChar[ 4 ]; //Allowed
float exampleArrayChar[ 6 ]; //NOT Allowed
int exampleArrayChar[ 8 ]; //Allowed

他说这背后的原因是因为计算机进行内存分配的方式。

计算机以四个字节为一组为每个数组元素分配内存地址/位置 - 因此在 2 个内存组中完成了一个 8 元素数组。

所以问题是,如果你创建一个大小为 6 的数组,它将分配 2 组 4,但随后将这些字节中的 2 个(8 个字节中的)标记为无效/无效,使它们无法使用,直到整个数组被释放记忆。

虽然这在我看来对于其他计算机数学来说是合理的(例如 1gb = 1024mb 而不是正好 1000),但我有兴趣知道:

  • 这是多么真实,以及这样做的好处是什么(如果有的话)
  • 这只是 C++ 吗?(我认为不会,但仍然值得一问)
  • 只是有关这方面的更多信息-例如,为什么是4?计算机数学通常不是二进制的,因此不是 2 的吗?

在网上环顾四周,我一直找不到任何主要用途或相关的东西。

4

4 回答 4

8
float exampleArrayChar[ 6 ]; //NOT Allowed

考虑到这float是 4 个字节(几乎普遍,由于浮点数广泛采用 IEEE-754 编码),任何数量的浮点数已经是 4 个字节的倍数。您的示例将是 24,并且没有问题。在 x86(和 x64)上,SSE 指令确实更喜欢 8 字节对齐的数据......再次拥有一个float大小为 6 个元素 = 24 字节的数组不会干扰这一点。

唯一真正对对齐很重要的较大倍数是缓存行的大小,它随实现而有很大差异(为 x86 编译的代码可能会发现自己运行在具有 32 字节、128 字节或其他缓存大小的 CPU 上,所有这些都来自同一台机器代码)。是的,缓存对齐可以产生很大的性能差异,但是与缓存行的对齐不一定更好,实际上对齐通常会更糟,因为它会引起缓存映射上的冲突,就性能影响而言,这类似于错误共享被关注到。

请参阅什么是“缓存友好”代码?以及为什么我的程序在恰好循环 8192 个元素时很慢?以及与这些相关的其他问题。

但是,一旦您的教授进入“任何评论都不允许”,您就应该在院长办公室要求退还您的学费。

于 2013-08-17T02:03:50.467 回答
3

假设你的老师真的告诉了你上面所说的,你的老师就会错(这根本不会让我感到惊讶)。然而,真实的是,当您从堆中分配内存时,正在分配的内存块可能是 2 的某个幂的倍数,因为否则内存最终会以不幸的方式碎片化,至少在使用通用用途时内存分配器。因此,您可能会浪费几个字节。但是,除非您有很多反对意见,否则我不会打扰这些细节:首先使用语义正确的方法使程序正确。

然而,处理这些问题的最佳方法不是一开始就使用数组,而是使用std::vector<T>or std::deque<T>

于 2013-08-17T01:29:27.990 回答
1

最近,当我在探索超级用户时,我遇到了一篇描述碎片的帖子,这导致我在 Wikipedia 上找到了这篇帖子。报价:

例如,内存只能以可被 4、8 或 16 整除的块的形式提供给程序,因此,如果程序请求可能 23 个字节,它实际上将获得 24 个块。当这种情况发生时,多余的内存将被转移到浪费。在这种情况下,不可用的内存包含在分配的区域内,因此称为内部碎片。

尽管如此,正如大多数人指出的那样,“节省”的空间量并不是什么大问题,因为在大多数现代系统中都存在大量内存(GB);最好根据程序的需要设计,而不是机器的需要。

于 2013-08-18T20:46:40.033 回答
1

那位老师有一些非常时髦(和错误的想法)。为了解释为什么是这样,让我们​​检查每个语句。

...我们的 C++ 老师...告诉我们应该使数组大小为 4 的倍数以提高效率...他说这背后的原因是因为计算机分配内存空间的方式(空间可能不是正确的工作 - 基本上是数组中每个元素的内存地址)

C(和 C++)允许如果您分配内存,无论类型如何,它都会在那里,否则会发生运行时错误。他可能会说,分配更多空间来容纳一些溢出错误将是一个好习惯(它不是)。然而,C 和 C++ 允许静态数组中的所有内存(我的意思是不是通过动态声明new(),尽管我不确定这个)数组是连续的。声明某事时,仅使用您的事需要使用的内存量(资源)。

计算机以四个一组为每个数组元素分配内存地址/位置 - 因此在 2 个内存组中完成了一个 8 元素数组(同样,组不是正确的词)

Anint至少有 4 个字节,这是唯一可以听到前面引用的句子。由于您可以通过引用来引用内存中的任何字节,因此没有明确需要将内存分成四个一组,除非出现一些环境问题。

虽然这在我看来对于其他计算机数学来说是合理的(例如 1gb = 1024mb 而不是正好 1000)......

尽管这最好在其他地方讨论,但 GB 和 GiB 是分开的;在维基百科上查看。但是,当涉及内存时,有一个非正式约定,即字节单元的倍数按 2 10、2 20、2 30等顺序排列。

最后,正如前面的评论者所说,在 C++ 中做事的正确方法是通过新的容器类,这std::vector<T>是最像数组的容器。将这种数组声明留给非常简单的东西或遗留 C 代码。

于 2013-08-17T01:53:52.530 回答