【问题标题】:Why is an integer always used as the controlling variable in a for loop?为什么整数总是用作 for 循环中的控制变量?
【发布时间】:2010-11-17 13:32:43
【问题描述】:

很多时候你知道你的循环永远不会运行超过 x 次,其中 x 可以用字节或短字节表示,基本上是小于 int 的数据类型。

为什么我们使用占用 32 位的 int(大多数语言),而像字节这样的东西只有 8 位就足够了。

我知道我们有 32 位和 64 位进程,因此我们可以轻松地在一次行程中获取值,但它仍然会消耗更多内存。或者我在这里错过了什么?

更新: 只是为了澄清。我知道速度方面没有区别。我问的是对内存消耗的影响。

【问题讨论】:

  • 真的吗?我见过的大多数代码都使用某种形式的无符号类型。
  • @Billy ONeal:在某些嵌入式微控制器上,无符号类型可能比有符号类型提供更好的性能,但代价是需要更加小心循环终止逻辑。另一方面,如果像 ARM 这样的处理器在 32 位寄存器中存储类似 uint16 的东西,它必须添加额外的代码来将值“裁剪”为 16 位。 int16 不需要这样的代码(因为当 int16 被分配一个超出 -32768..32767 范围的值时允许发生任何事情,编译器可以让它的值做任何方便的事情)。
  • 你是否创建了足够多的循环计数器来改变它们的类型对内存消耗有可见的影响?如果是这样,那么我认为您遇到的问题不仅仅是使用超出必要的类型。
  • @supercat:我并不是说 unsigned 更好——它们在大多数机器上都会产生相同的效果。但是,在我知道的大多数语言中,任何标准类型的容器都将大小或长度作为无符号类型返回,并且尝试在此类循环中使用 int 会导致编译器警告。 (因为比较中的有符号/无符号不匹配)
  • @John Bode。一点都不。我只是想要一些教育。我时不时地质疑我们为什么要这样做。

标签: for-loop coding-style memory-optimization


【解决方案1】:

在 C 中,“int”被定义为当前机器最有效的整数类型。

它通常与CPU的寄存器匹配,这样是最有效的。

使用较小类型的整数值可能会导致 CPU 级别的一些位移或位掩码,因此您不会获得任何收益...

【讨论】:

  • 实际上,它被定义为“自然字长”,它可能是也可能不是最有效的类型。对于最高效的类型,使用 C99 的 fastint_t。
  • 揭开这些编程细节的神秘面纱真的很令人兴奋
  • 我更多的是询问内存消耗。
  • 内存消耗?请参阅 larsmans 的回答:通常您的循环计数器在内存中的寄存器中很少。无论如何对齐问题可能会导致您的变量使用比您想象的更多。
【解决方案2】:

访问与本机字大小相同的整数大小将是最有效的。使用一个字节几乎肯定需要与本机字大小一样多的空间,并且需要移位和屏蔽才能访问,因此没有任何好处。

实际上,除非您有非常非常大的循环或严格的时序限制,否则不会有太大的不同。

但一如既往,请使用最易读的内容,并首先使用基准/配置文件...

【讨论】:

  • 我非常怀疑优化编译器不会简单地为char 分配空间char,如果实际上int 更有效的话。 OTOH,在我知道的大多数架构上,intchar 之间的速度没有差异。
【解决方案3】:

我几乎总是使用int,除非有很好的理由不使用,因为每个人都总是使用它。这是为了避免下一个开发人员不得不花时间思考他为什么不在这里使用int,我需要了解一些特殊原因

我的代码越标准,以后越容易阅读。

【讨论】:

  • 好点。大多数人也知道并且可以理解 i++ 语法。
【解决方案4】:

在许多情况下,循环计数器只消耗一个处理器寄存器。将类型更改为 8 位或 16 位整数不会改变这一点,因为寄存器具有固定大小(32 位平台上的 32 位等)。

有时,循环计数器可能会放在 RAM 中,例如当您从循环中调用函数时。那么,是的,您可能会浪费一些字节,但通常不足以担心。当使用不同于 int 的东西时,存储和加载循环计数器实际上可能会更慢。

【讨论】:

    【解决方案5】:

    Java Language Specification 而言,关于longdouble 的使用有一点值得注意:

    出于 Java 的目的 编程语言记忆模型 单次写入非易失性 long 或 双精度值被视为两个 单独写入:每个 32 位一个 一半。这可能会导致一种情况 线程看到前 32 位的位置 一次写入的 64 位值,以及 另一个写入的第二个 32 位。 volatile long 的写入和读取 双精度值始终是原子的。 对引用的写入和读取是 总是原子的,不管是否 它们被实现为 32 或 64 位 价值观。鼓励虚拟机实现者 避免拆分它们的 64 位值 在可能的情况。程序员是 鼓励声明共享 64 位 值作为 volatile 或 synchronize 他们的程序正确地避免 可能的并发症。

    很明显,这使得在循环变量中使用longdouble 的效率低于Java 内存模型中的int,但实现的性能可能会有所不同。

    【讨论】:

      【解决方案6】:

      我很想在这里添加一些东西,即使它是一个非常古老的线程。我不完全同意“我知道速度方面没有区别”。实际上,在 for 循环中经常有数组索引,例如 in

      for (i=0; i<len; i++) s = A[i]
      

      然后,即使您的数组大小小于 128,无论iint 还是byte,您都会看到显着的速度差异。实际上,要在A[i] 中执行指针运算,处理器必须将整数转换为与指针大小相同的东西。如果整数已经具有相同的大小,则不存在导致更快代码的转换。 在 64 位机器上,通过在非常小的数组上使用 long int 而不是 char(C/C++ 程序)上的循环索引,我似乎可以将程序加速 20%。

      【讨论】:

      • 这很有趣。谢谢
      猜你喜欢
      • 2020-12-24
      • 2013-08-03
      • 1970-01-01
      • 1970-01-01
      • 2011-03-26
      • 2020-08-31
      • 2019-10-09
      • 2015-04-08
      • 1970-01-01
      相关资源
      最近更新 更多