使用整数作为循环计数器变量更好吗?

我记得在某处读取最好使用整数作为循环计数器变量而不是char或short。 如果是,为什么? 它是否提供任何优化好处?

通常,编译器会使int成为一个很好的大小,以便放入CPU的通用寄存器中。 这通常会导致快速访问。

当然,没有任何保证。 编译器可以自由地执行很多操作,包括我猜测,将一些使用char的代码推广到更大的类型。 所以差异可能不重要。

实际上,对于编译器的答案,您应该查看它输出的程序集。

在具有4个字节(int)变量的32位架构操作中,变量通常更快。 这主要是由于寄存器的大小和内存对齐。 在64位架构中,它将(应该)自动生成64位整数。

Alexey *是对的,使用与架构宽度相同的类型通常更快(即32位系统的int32)

此外,如果你使用char即

 for(char i=0;i 

您(或同事)在一个月的时间内回到代码并将最大值更改为高位,导致溢出和恼人的错误的可能性很小;)

山姆

*和我写这篇文章时回答的所有人!

通常可以预期int类型是平台上实现最快的整数类型,因此应该是默认选择。

来自K&R,第2版,p。 36:

int :一个整数,通常反映主机上整数的自然大小。

size_t类型用于循环计数器会更好。 它将扩展到64位。

有没有注意到C标准对整数大小的影响有多大? 这一事实促使设备驱动程序工程师和从事通信协议工作的人员感到头晕目眩,因为他们认为语言应该清楚地定义对象的大小。

C表示int是实现体系结构的自然大小。 这意味着它将至少与任何其他尺寸一样有效地处理。 采用x86架构:32位程序中使用的short (16位整数)包含执行额外“大小覆盖”修改的指令。 所以代码有更多的字节,但通常没有性能损失。 除非额外的字节导致缓存行溢出….

x86为char计数器生成的代码通常包括增量后的屏蔽,以确保它保持8位。 似乎使用较小的变量会更小更紧凑,但x86和其他几个常见CPU的情况并非如此。

担心在担心这些问题之前让你的循环正确。 通过更改intcharshort之间的循环计数器的类型,您更有可能在循环边界中出现一个off-by-one错误,而不是速度或代码大小的可测量差异。 所以首先要担心正确性。

也就是说,除非你有理由不这样做,否则默认使用intunsigned int – 但是我之所以这样说是因为你不太可能需要担心溢出或者使用较大的类型而不是因为它可能更快(尽管它可能更快)它可能)。

在某些情况下, char s(甚至short s)的溢出问题将产生非终止循环。

这实际上取决于您为代码编写的平台。 最好使用的类型是将其与您的平台相匹配。 即,如果您正在编写一个简单的8位微代码,也许使用uint8_t比使用uint16_t更好。

通常,int是循环的正确选择。 它可能有两个原因:

  1. 它可能比必要的大。 SDCC支持一些8位处理器,例如Z80,它允许8位访问寄存器,尽管sizeof(int)= 2。 如果循环变量不需要超过8位,那么使用大小为(char)= 1的字符允许优化器更多地填充寄存器空间,从而产生更快的代码。
  2. 它可能太小了。 如果整数是16位,那么你可能会有多次循环运行。

所以,是的,根据您的架构,您可能需要考虑有多大的整数。 但通常你没有。

这实际上取决于你的循环在做什么。 以此循环为例:

 typedef struct _SomeData { /* some data here */ } SomeData; void SomeFunction (SomeData *array_of_data, int number_of_elements) { int i; for (i = 0 ; i < number_of_elements ; ++i) { DoSomethingWithData (&array_of_data [i]); } } 

有些编译器会很好地优化上述内容。 但是一些编译器,特别是针对小众嵌入式微处理器的编译器,将产生可怕的无效代码。 它可以重写为:

 void SomeFunction (SomeData *array_of_data, int number_of_elements) { SomeData *current = array_of_data, *end = &array_of_data [number_of_elements]; while (current < end) { DoSomethingWithData (current++); } } 

它根本不使用整数,并且无论编译器如何都更有可能产生良好的输出(现代编译器可能会将整数版本优化为如上所述)。

因此,循环并不总是需要整数,最好的优化总是不做必要的事情。 但是,如果循环明确需要整数,则int类型通常会提供最佳结果。

当然,您必须始终使用分析器来确保代码的性能以及更改类型是否有所不同。