【发布时间】:2009-11-29 20:51:19
【问题描述】:
是有历史原因还是什么?我见过很多次类似char foo[256]; 或#define BUF_SIZE 1024 的东西。即使我大多只使用 2n 大小的缓冲区,主要是因为我认为它看起来更优雅,这样我就不必考虑具体的数字。但我不太确定这是否是大多数人使用它们的原因,更多信息将不胜感激。
【问题讨论】:
标签: c data-structures size buffer
是有历史原因还是什么?我见过很多次类似char foo[256]; 或#define BUF_SIZE 1024 的东西。即使我大多只使用 2n 大小的缓冲区,主要是因为我认为它看起来更优雅,这样我就不必考虑具体的数字。但我不太确定这是否是大多数人使用它们的原因,更多信息将不胜感激。
【问题讨论】:
标签: c data-structures size buffer
可能有很多原因,尽管很多人会如你所说的那样只是出于习惯。
它非常有用的一个地方是循环缓冲区的有效实现,尤其是在 % 运算符很昂贵的架构上(那些没有硬件划分 - 主要是 8 位微控制器)。通过在这种情况下使用 2^n 缓冲区,模数只是对高位进行位掩码的情况,或者在 256 字节缓冲区的情况下,只需使用 8 位索引并让它环绕。
在其他情况下,与页面边界、缓存等对齐可能会为某些架构的优化提供机会——但这将是非常特定于架构的。但可能只是这样的缓冲区为编译器提供了优化的可能性,所以所有其他条件都相同,为什么不呢?
【讨论】:
缓存行通常是 2 的倍数(通常是 32 或 64)。是该数量整数倍的数据将能够适应(并充分利用)相应数量的高速缓存行。您可以将更多数据打包到缓存中,性能就越好。所以我认为以这种方式设计结构的人正在为此进行优化。
【讨论】:
除了其他人提到的另一个原因是,SSE 指令需要多个元素,并且输入的元素数量始终是 2 的幂。将缓冲区设为二的幂可以保证您不会读取未分配的内存。这仅适用于您实际使用 SSE 指令的情况。
我认为,在大多数情况下,最重要的原因是程序员喜欢二的幂。
【讨论】:
这对哈希表很有帮助,因为您计算索引的模数是大小,如果该大小是 2 的幂,则可以使用简单的 bitwise-and 或 @987654321 计算模数@ 而不是使用实现% 运算符的慢得多的除类指令。
看一本旧的 Intel i386 书,and 是 2 个周期,div 是 40 个周期。由于分工的基本复杂性要大得多,今天的差异仍然存在,尽管 1000 倍更快的整体周期时间往往会掩盖即使是最慢的机器操作的影响。
也有一段时间,malloc 开销偶尔会被大量避免。直接从操作系统获得的分配将是(仍然是)特定数量的页面,因此 2 的幂可能会充分利用分配粒度。
而且,正如其他人所指出的,程序员喜欢二的幂。
【讨论】:
我能想到几个原因:
SIZE_BYTE+ARRAY 将是最有效的,其中大小字节告诉您数组的大小。这意味着数组可以是 1 到 256 之间的任意大小。好的,这些点有点混乱。如果您需要进一步解释,请告诉我,尤其是第 4 点,IMO 最重要。
【讨论】:
因为电子学中以 2 为底的算术很简单(另请阅读成本):左移(乘以 2)、右移(除以 2)。
在 CPU 域中,许多构造都围绕以 2 为底的算术。访问内存结构的总线(控制和数据)通常在 2 次幂上对齐。电子设备(例如 CPU)中逻辑实现的成本使得以 2 为基数的算术具有吸引力。
当然,如果我们有模拟计算机,情况就会不同。
仅供参考:位于 X 层的系统的属性是位于下面的系统的 server 层属性的直接结果,即 layer
例如可以在“编译器”级别操作的属性是继承并派生自其下系统的属性,即 CPU 中的电子设备。
【讨论】:
我打算使用 shift 论点,但可以想出一个很好的理由来证明它的合理性。
缓冲区是 2 的幂的一个优点是循环缓冲区处理可以使用简单的与而不是除:
#define BUFSIZE 1024
++index; // increment the index.
index &= BUFSIZE; // Make sure it stays in the buffer.
如果不是 2 的幂,则有必要使用除法。在过去(现在是小筹码)很重要。
【讨论】:
页面大小为 2 的幂也很常见。
在 linux 上,我喜欢在执行诸如分块缓冲区并将其写入套接字或文件描述符之类的操作时使用 getpagesize()。
【讨论】:
这是一个很好的以 2 为底的整数。就像 10、100 或 1000000 是很好的以 10 为底的整数一样。
如果它不是 2 的幂(或接近的值,例如 96=64+32 或 192=128+64),那么您可能想知道为什么会增加精度。不是以 2 为基础的舍入大小可能来自外部约束或程序员的无知。你会想知道它是哪一个。
其他答案也指出了许多在特殊情况下有效的技术原因。此处不再赘述。
【讨论】:
在哈希表中,2^n 以某种方式更容易处理关键冲突。通常,当发生键冲突时,您要么制作子结构,例如具有相同哈希值的所有条目的列表;或者您找到另一个空闲插槽。您可以将 1 添加到插槽索引,直到找到空闲插槽;但是这种策略并不是最优的,因为它会创建阻塞位置的集群。更好的策略是计算第二个哈希数h2,使得gcd(n,h2)=1;然后将 h2 添加到插槽索引,直到找到一个空闲插槽(环绕)。如果 n 是 2 的幂,找到满足 gcd(n,h2)=1 的 h2 很容易,每个奇数都可以。
【讨论】: