Я не забываю читать где-нибудь, что лучше использовать целые числа в качестве переменных счетчика цикла, а не символа или короткий. Если да, почему? Это предоставляет какие-либо преимущества оптимизации?
Обычно компилятор делает int
подходящим размером для помещения в один из регистров общего назначения вашего процессора. Обычно это приводит к быстрому доступу.
Конечно, нет никаких гарантий. Компилятор может делать множество вещей, в том числе, я полагаю, продвигать часть вашего кода, в которой используется char
, в более крупный тип. Так что разница может даже не иметь значения.
На самом деле, чтобы получить ответ, верный для вашего компилятора, вы должны посмотреть на выводимую им сборку.
В 32-битной архитектуре операции с 4-байтовыми (int) переменными обычно выполняются быстрее. В основном это связано с размером регистров и выравниванием памяти. В 64-битной архитектуре int будет (должен) автоматически стать 64-битным целым числом.
Было бы еще лучше использовать тип size _ t
для счетчиков циклов. Он будет масштабироваться до 64 бит.
В некоторых случаях проблемы переполнения с char
s (или даже short
s) приводят к образованию не завершающих петель.
Алексей * прав, обычно быстрее использовать тип той же ширины, что и архитектура (т.е. int32 для 32-разрядной системы)
Кроме того, если вы используете символ, т.е.
for(char i=0;i<max;++i)
, есть небольшая вероятность того, что вы (или коллега) вернется к коду через месяц и изменит максимум на что-то высокое, вызывая переполнение и раздражающую ошибку;)
Сэм
* и все остальные, кто ответил, пока я писал это!
Обычно можно ожидать, что тип int
будет самым быстрым реализованным целочисленным типом на вашей платформе, и поэтому он должен быть выбором по умолчанию.
Из K&R, 2-е издание, с. 36:
int
: целое число, обычно отражающее естественный размер целых чисел на хост-машине.
Вы когда-нибудь замечали, что стандарт C не совсем точен в отношении размера целых чисел? Этот факт приводит в замешательство разработчиков драйверов устройств и тех, кто работает над протоколами связи, поскольку они считают, что язык должен четко определять размер объектов.
C говорит, что int
является естественным размером для архитектуры реализации. Это означает, что с ним будут обращаться не менее эффективно, чем с любым другим размером. Возьмем архитектуру x86: short
(16-битное целое число), используемое в 32-битной программе, содержит инструкции, выполняющие дополнительную модификацию «переопределения размера». Таким образом, код имеет больше байтов, хотя обычно без потери производительности. Если только лишние байты не вызывают переполнение строки кэша ....
Сгенерированный x86 код для счетчика char
обычно включает маскировку после приращения, чтобы гарантировать, что он останется 8 бит. Может показаться, что использование меньшей переменной будет меньше и труднее, но это не относится к x86 и нескольким другим распространенным процессорам.
Это действительно зависит от платформы, для которой вы пишете код. Лучше всего использовать его в соответствии с вашей платформой. То есть, если вы пишете код для простого 8-битного микроконтроллера, возможно, использование uint8_t лучше, чем использование uint16_t.
Было бы даже лучше использовать тип size_t
для счетчиков циклов. Он будет масштабироваться до 64 бит.
Побеспокойтесь о правильном выполнении циклов, прежде чем беспокоиться об этих вещах. Вы с гораздо большей вероятностью получите ошибку в границах цикла, чем ощутимую разницу в скорости или размере кода при изменении типа счетчика цикла между int
, char
или short
. Так что сначала побеспокойтесь о корректности.
Учитывая это, по умолчанию используйте int
или unsigned int
, если у вас нет причин поступать иначе - но я говорю так, потому что вам реже придется беспокоиться о переполнении или обводке при использовании большего типа, а не потому, что это может быть быстрее (хотя может).
Обычно int - правильный выбор для цикла. Этого может не быть по двум причинам:
Итак, да, вам, возможно, придется подумать о том, насколько велики целые числа, в зависимости от вашей архитектуры. Но обычно этого не происходит.
Это действительно зависит от того, что делает ваш цикл. Возьмем, к примеру, этот цикл:
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 обычно обеспечивает лучший результат.
Конечно, вы всегда должны использовать профилировщик, чтобы быть уверенным в производительности кода и в том, имеет ли изменение типа какое-либо значение.
В некоторых случаях проблемы переполнения с char
s (или даже short
s) приводят к возникновению незавершенных циклов.