Почему выражение вместо константы, в условном цикле C for-loop?


во многих соревнованиях по программированию я видел, как люди пишут этот тип for - loop

for(i = 0; i < (1 << 7); i++)

если я чего-то не хватает, это то же самое, что

for(i = 0; i < 128; i++)

зачем использовать (1 << 7) версия?
не вычисляет ли условие каждый раз ненужные накладные расходы?

7 57

7 ответов:

Да, они эквивалентны по поведению.

тогда почему люди используют версию (1

Я думаю, они используют его для документирования это сила 2.

вычисление условия каждый раз должно быть накладными расходами! Я не могу найти причину этого!

не совсем, любой нормальный компилятор заменит 1 << 7 by 128 и поэтому оба цикла будут иметь одинаковые характеристики.

(C11, 6.6p2) "константное выражение может быть вычислено во время трансляции, а не во время выполнения, и соответственно может использоваться в любом месте, где может быть константа."

давайте переведем каждый из этих вариантов на простой английский язык:

for(i = 0; i < (1 << 7); i++) // For every possible combination of 7 bits
for(i = 0; i < 128; i++)      // For every number between 0 and 127

поведение во время выполнения должно быть идентичным в обоих случаях.

на самом деле, предполагая приличный компилятор, даже ассемблерный код должен быть идентичен.

таким образом, первый вариант по существу используется только для того, чтобы "сделать заявление".

вы можете также использовать второй вариант и добавить комментарий выше.

1 << 7 является постоянным выражением, компилятор обрабатывает его как 128, нет никаких накладных расходов во время выполнения.

без тела цикла, трудно сказать, почему автор его использует. Возможно, это цикл, который повторяет что-то связанное с 7 битами, но это только мое предположение.

тогда почему люди используют версию (1

это форма документации, это не магическое число, но 2^7(два в седьмой степени), который имеет смысл для тех, кто написал код. Современный оптимизирующий компилятор должен генерировать один и тот же код для обоих примеров, поэтому нет никаких затрат на использование этой формы, и есть преимущество добавления контекста.

используя godbolt мы можем проверить это действительно так, по крайней мере, для нескольких версий gcc,clang и icc. Используя простой пример с побочными эффектами, чтобы убедиться, что код не полностью оптимизирован:

#include <stdio.h>

void forLoopShift()
{
  for(int i = 0; i < (1 << 7); i++)
  {
    printf("%d ", i ) ;
  }
}

void forLoopNoShift()
{
  for(int i = 0; i < 128; i++)
  {
        printf("%d ", i ) ;
  }
}

для соответствующей части кода мы видим, что они оба генерируют следующее посмотреть это видео:

cmpl    8, %ebx

у нас целочисленное константное выражение как определено в проекте стандартного раздела C11 6.6постоянная выражения он говорит:

целочисленное константное выражение 117) должно иметь целочисленный тип и иметь только операнды это целочисленные константы, константы перечисления, символьные константы, sizeof выражения, результаты которых являются целочисленными константами, [...]

и:

постоянные выражения не должны содержать присваивание, инкремент, декремент, вызов функции, или операторы запятой, за исключением тех случаев, когда они содержатся в пределах подвыражение, которое не является оцененный.115)

и мы видим, что постоянное выражение может быть оценено во время перевода:

постоянное выражение может быть вычислено во время перевода, а не во время выполнения, и соответственно может использоваться в любом месте, где может быть константа.

for(i = 0; i

и

for(i = 0; i

дает такую же производительность, но разработчик может воспользоваться огромным преимуществом в случае, если (i = 0; i

for(int k = 0; k < 8; k++)
{
  for(int i = 0; i < (1 << k); i++)
   {
    //your code
    }

}

теперь он находится в верхнем пределе внутреннего цикла, т. е. (1

компилятор один и тот же код для обоих случаев. вы, вероятно, хотите использовать различные формы в зависимости от контекста.

  1. можно использовать NUM_STEPS или NUM_ELEMENTS_IN_NETWORK_PACKET когда это постоянная часть или выбор дизайна в ваш алгоритм, который вы хотите прояснить.
  2. или вы можете написать 128, чтобы было понятно, что это 128, постоянной.
  3. или писать 1 << 7 если вы находитесь на конкурсе и тест сказал что-то вроде " запустите его 2^7 раз".

или, вы можете хвастаться, что вы знаете битовые операции!

по моему скромному мнению, Программирование похоже на написание письма для двух человек, компилятора и человека, который должен будет его прочитать. То, что вы имеете в виду, должно быть ясно для обоих.

он вычисляется препроцессором, так как оба операнда являются постоянными.

но если вы собираетесь использовать число вместо битового сдвига, не должно ли это быть 0x0100?