Если одно использование <или <= в для [замкнутого] круга

Будет работать следующий код:

#define EVAL(...) __VA_ARGS__
#define EVAL2(...) EVAL(__VA_ARGS__)
#define EMPTY()
#define DELAYED_CALL(F, ...) F EMPTY()(__VA_ARGS__)

#define BB(i,n) i +
#define AA(i,n) i + (MYLIST(BB) 0) +

#define MYLIST(XX) \
    DELAYED_CALL(XX, 1, hello) \
    DELAYED_CALL(XX, 2, world)

int foo = EVAL2(MYLIST(AA)) 0;

Вывод: int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;

К сожалению, у меня нет глубокого понимания , почему это работает; Я только что попробовал несколько трюков, которые, как правило, помогают в подобных случаях. Но я могу объяснить кое-что из этого.

Иногда макрос помечается как «не подлежащий дальнейшему расширению». Флаг обычно устанавливается, когда вы начинаете расширять его, и сбрасывается, когда расширение заканчивается. Это имеет тенденцию предотвращать рекурсию.

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

Мы можем обойти первую проблему, отложив расширение макроса до точки, где флаг не вызовет никаких проблем, добавив второй макрос в , создавая вызов макроса при его оценке. Вот что делает DELAYED_CALL. Но при этом мы сталкиваемся со второй проблемой, поэтому нам нужно добавить несколько вызовов в EVAL для повторного сканирования макроса (аргументы к функциональному макросу всегда сканируются, поэтому передается последовательность токенов в функциональный макрос, который просто выводит свои аргументы, вызывает повторное сканирование).

1117 Иногда нам нужно пару повторных проверок, чтобы все работало. EVAL2(X) это просто сокращение от EVAL(EVAL(X)). Иногда потребуется больше уловок.

Приведенный ниже код немного разъясняет, что происходит. Обратите внимание, что версии MYLIST2 требуется на один меньше EVAL; это потому, что AA вызывает MYLIST, а MYLIST2 - тот, у которого установлен флаг нарушителя.

#define EVAL(...) __VA_ARGS__
#define EVAL2(...) EVAL(__VA_ARGS__)
#define EVAL3(...) EVAL2(__VA_ARGS__)
#define EMPTY()
#define DELAYED_CALL(F, ...) F EMPTY()(__VA_ARGS__)

#define BB(i,n) i +
#define AA(i,n) i + (MYLIST(BB) 0) +

#define MYLIST(XX) \
    DELAYED_CALL(XX, 1, hello) \
    DELAYED_CALL(XX, 2, world)

#define MYLIST2(XX) \
    XX(1, hello) \
    XX(2, world)

% MYLIST
int foo = MYLIST(AA) 0;
int foo = EVAL(MYLIST(AA)) 0;
int foo = EVAL2(MYLIST(AA)) 0;

% MYLIST2
int foo = MYLIST2(AA) 0;
int foo = EVAL(MYLIST2(AA)) 0;
int foo = EVAL2(MYLIST2(AA)) 0;

Вывод этого будет:

% MYLIST
int foo = AA (1, hello) AA (2, world) 0;
int foo = 1 + (BB (1, hello) BB (2, world) 0) + 2 + (BB (1, hello) BB (2, world) 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;

% MYLIST2
int foo = 1 + (BB (1, hello) BB (2, world) 0) + 2 + (BB (1, hello) BB (2, world) 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;

(Знаки% не являются чем-то особенным. Я просто хотел, чтобы комментарии отображались в выводе, а комментарии в стиле C удалить во время предварительной обработки.)

Дополнительная литература . Автор статьи понимает это гораздо лучше, чем я.

122
задан 4 revs, 2 users 100% 8 October 2008 в 21:29
поделиться

38 ответов

Первое является больше идиоматичный . В частности, это указывает (в смысле на основе 0) на количество повторений. При использовании чего-то на основе 1 (например, JDBC, IIRC) я мог бы испытать желание использовать < =. Так:

for (int i=0; i < count; i++) // For 0-based APIs

for (int i=1; i <= count; i++) // For 1-based APIs

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

287
ответ дан 24 November 2019 в 01:18
поделиться

Не используйте магические числа.

, Почему это 7? (или 6 в этом отношении).

используют корректный символ для числа, которое Вы хотите использовать...

, В этом случае я думаю, что лучше использовать

for ( int i = 0; i < array.size(); i++ )
1
ответ дан 24 November 2019 в 01:18
поделиться

Создание привычки к использованию < сделает это последовательным и для Вас и для читателя, когда Вы выполните итерации через массив. Будет более просто для всех иметь стандартную конвенцию. И если Вы используете язык с массивами на основе 0, затем < конвенция.

Это почти наверняка имеет значение больше, чем какое-либо различие в производительности между < и < =. Стремитесь к функциональности и удобочитаемости сначала, затем оптимизируйте.

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

1
ответ дан 24 November 2019 в 01:18
поделиться

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

РЕДАКТИРОВАНИЕ: я вижу, что другие не соглашаются. Для меня лично, мне нравится видеть фактические индексы в циклической структуре. Возможно, это - потому что это более напоминает о Perl 0..6 синтаксис, который я знаю, эквивалентно (0,1,2,3,4,5,6). Если я вижу 7, я должен проверить оператор рядом с ним, чтобы видеть, что на самом деле индекс 7 никогда не достигается.

4
ответ дан 24 November 2019 в 01:18
поделиться

Замеченный с точки зрения оптимизации это не имеет значения.

Замеченный с точки зрения стиля кода я предпочитаю <. причина:

for ( int i = 0; i < array.size(); i++ )

настолько более читаемо, чем

for ( int i = 0; i <= array.size() -1; i++ )

также < дает Вам количество повторений немедленно.

Другое голосование за < это, Вы могли бы предотвратить много случайных ошибок off-one.

18
ответ дан 24 November 2019 в 01:18
поделиться

Я всегда использую < array.length, потому что легче читать, чем < = array.length-1.

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

27
ответ дан 24 November 2019 в 01:18
поделиться

Я предпочитаю:

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

я думаю, что это переводит с большей готовностью в "итерацию через цикл 7 раз".

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

5
ответ дан 24 November 2019 в 01:18
поделиться

Это не имеет никакого эффективного значения когда дело доходит до производительности. Поэтому я использовал бы, какой бы ни легче понять в контексте проблемы, которую Вы решаете.

6
ответ дан 24 November 2019 в 01:18
поделиться

@Chris, Ваш оператор о.Length том, чтобы быть дорогостоящим в.NET на самом деле неверен и в случае простых типов полная противоположность.

int len = somearray.Length;
for(i = 0; i < len; i++)
{
  somearray[i].something();
}

на самом деле медленнее, чем

for(i = 0; i < somearray.Length; i++)
{
  somearray[i].something();
}

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

10
ответ дан 24 November 2019 в 01:18
поделиться

Я всегда предпочитал:

for ( int count = 7 ; count > 0 ; -- count )
1
ответ дан 24 November 2019 в 01:18
поделиться

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

я не волновался бы о ли "<"; более быстро, чем "< =", просто пойдите для удобочитаемости.

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

for (int i = 0; i < this->GetCount(); i++)
{
  // Do something
}

Для увеличения производительности можно немного перестроить его к:

const int count = this->GetCount();
for (int i = 0; i < count; ++i)
{
  // Do something
}

Уведомление удаление GetCount () от цикла (потому что это будет запрошено в каждом цикле), и изменение "меня ++" к "++ я".

4
ответ дан 24 November 2019 в 01:18
поделиться

В Java 1.5 можно просто сделать

for (int i: myArray) {
    ...
}

так для случая массива, который Вы не должны волновать.

4
ответ дан 24 November 2019 в 01:18
поделиться

Я помню со своих дней, когда мы сделали 8 086 блоков в колледже, это было более производительно, чтобы сделать:

for (int i = 6; i > -1; i--)

как был операция JNS , которая означает Переход если Никакой Знак. Используя это означал, что не было никакого поиска памяти после каждого цикла, чтобы получить сравнительное значение и не выдержать сравнение также. В эти дни большинство компиляторов оптимизирует использование регистра, таким образом, вещь памяти больше не важна, но Вы все еще добираетесь, необязательное выдерживают сравнение.

способом поместить 7 или 6 в Вашем цикле представляет" магическое число ". Для лучшей удобочитаемости необходимо использовать константу с Поглощенным Разоблачающим Именем. Как это:

const int NUMBER_OF_CARS = 7;
for (int i = 0; i < NUMBER_OF_CARS; i++)

РЕДАКТИРОВАНИЕ: Люди aren’t получение вещи блока так более полный пример, очевидно, требуются:

, Если мы делаем для (я = 0; я < = 10; я ++), необходимо сделать это:

    mov esi, 0
loopStartLabel:
                ; Do some stuff
    inc esi
                ; Note cmp command on next line
    cmp esi, 10
    jle exitLoopLabel
    jmp loopStartLabel
exitLoopLabel:

, Если мы делаем для (интервал i = 10; i>-1; я-), затем можно сойти с рук это:

    mov esi, 10
loopStartLabel:
                ; Do some stuff
    dec esi
                ; Note no cmp command on next line
    jns exitLoopLabel
    jmp loopStartLabel
exitLoopLabel:

я просто проверил, и компилятор C++ Microsoft не делает этой оптимизации, но это делает, если Вы делаете:

for (int i = 10; i >= 0; i--) 

, Таким образом, мораль - то, если Вы используете Microsoft C ++ вЂ, и возрастаете или убываете, не имеет никакого значения, для получения быстрого цикла, который необходимо использовать:

for (int i = 10; i >= 0; i--)

, а не любой из них:

for (int i = 10; i > -1; i--)
for (int i = 0; i <= 10; i++)

, Но откровенно получение удобочитаемости "для (интервал i = 0; я < = 10; я ++)", обычно намного более важно, чем пропавшие без вести одной команды процессора.

†Другие компиляторы могут сделать разные вещи.

55
ответ дан 24 November 2019 в 01:18
поделиться

Во-первых, не используйте 6 или 7.

Лучше для использования:

int numberOfDays = 7;
for (int day = 0; day < numberOfDays ; day++){

}

В этом случае это лучше, чем использование

for (int day = 0; day <= numberOfDays  - 1; day++){

}

Еще лучше (Java / C#):

for(int day = 0; day < dayArray.Length; i++){

}

И еще лучше (C#)

foreach (int day in days){// day : days in Java

}

обратный цикл действительно быстрее, но так как более трудно читать (если не Вами другими программистами), лучше избежать в. Особенно в C#, Java...

3
ответ дан 24 November 2019 в 01:18
поделиться

Я соглашаюсь с толпой, заявляющей, что эти 7 имеют смысл в этом случае, но я добавил бы, что в случае, где эти 6 важно, скажите, что Вы хотите ясно дать понять, что Вы только действуете на объекты до 6-го индекса, затем < = лучше, так как это делает 6 легче видеть.

2
ответ дан 24 November 2019 в 01:18
поделиться

Edsger Dijkstra записал статью об этом назад в 1982, где он приводит доводы ниже < = я < верхний:

существует самое маленькое натуральное число. Исключение нижней границы — как в b) и d) — вызывает для подпоследовательности, запускающейся в самом маленьком натуральном числе нижняя граница, как упомянуто в область неестественных чисел. Это ужасно, таким образом, для нижней границы мы предпочитаем в‰ ¤ как в a) и c). Рассмотрите теперь подпоследовательности, запускающиеся в самом маленьком натуральном числе: включение верхней границы затем вынудило бы последнего быть неестественным к тому времени, когда последовательность уменьшилась к пустой. Это ужасно, таким образом, для верхней границы мы предпочитаем < как в a) и d). Мы приходим к заключению, что конвенция a) состоит в том, чтобы быть предпочтена.

4
ответ дан 24 November 2019 в 01:18
поделиться

Это непосредственно подпадает под категорию "Взгляд Неверного кода Создания Неправильно" .

На основанных на нуле языках индексирования, таких как Java или люди C# приучены к вариациям на index < count условие. Таким образом усиление этой defacto конвенции сделало бы ошибки диапазона более очевидными.

Относительно производительности: любой хороший компилятор, стоящий его объема потребляемой памяти, должен представить, такие как надуманный вопрос.

2
ответ дан 24 November 2019 в 01:18
поделиться

Путь назад в колледже, я помню, что что-то об этих двух операциях, являющихся подобным в, вычисляет время на ЦП. Конечно, мы перекрикиваем на уровне ассемблера.

Однако, если Вы говорите C# или Java, я действительно не думаю, что каждый будет повышением скорости по другому, Несколько наносекунд, которые Вы получаете, наиболее вероятны не стоящие любого беспорядка, который Вы представляете.

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

2
ответ дан 24 November 2019 в 01:18
поделиться

Как небольшое в стороне, когда цикличное выполнение через массив или другой набор в .NET, я нахожу

foreach (string item in myarray)
{
    System.Console.WriteLine(item);
}

быть более читаемым, чем числовое для цикла. Это, конечно, предполагает, что сам фактический встречный Интервал не используется в коде цикла. Я не знаю, существует ли изменение производительности.

2
ответ дан 24 November 2019 в 01:18
поделиться

Существует много серьезных оснований для записи i< 7. Наличие номера 7 в цикле, который выполняет итерации 7 раз, хорошо. Производительность эффективно идентична. Почти все пишут i< 7. Если Вы пишете для удобочитаемости, используйте форму, которую все распознают немедленно.

1
ответ дан 24 November 2019 в 01:18
поделиться

В C++ я предпочитаю использовать !=, который применим со всеми контейнерами STL. Не все итераторы контейнера STL меньше сопоставимы.

4
ответ дан 24 November 2019 в 01:18
поделиться

Оба из тех циклов выполняют итерации 7 раз. Я сказал бы, что тот с 7 в нем более читаем/более ясен, если у Вас нет действительно серьезного основания для другого.

72
ответ дан 24 November 2019 в 01:18
поделиться

Как люди заметили, нет никакого различия ни в одной из этих двух альтернатив, которые Вы упомянули. Только для подтверждения этого я сделал некоторое простое сравнительное тестирование в JavaScript.

Вы видите результаты здесь . То, что не ясно из этого, - то, что, если я подкачиваю положение 1-х и 2-х тестов, результатов для тех 2 тестов подкачка, это - ясно проблема памяти. Однако 3-й тест, тот, где я инвертирую порядок повторения, ясно быстрее.

1
ответ дан 24 November 2019 в 01:18
поделиться

Как все говорят, это обычно для использования 0-индексируемых итераторов даже для вещей за пределами массивов. Если все начинается в 0 и заканчивается в n-1, и нижние границы всегда <=, и верхние границы всегда <, существует так намного меньше взглядов, что необходимо сделать при рассмотрении кода.

1
ответ дан 24 November 2019 в 01:18
поделиться

Вы могли также использовать != вместо этого. Тем путем Вы получите бесконечный цикл, если Вы совершите ошибку в инициализации, заставляя ошибку быть замеченными ранее и какие-либо проблемы, это вызывает, чтобы быть ограниченным застреванием в цикле (вместо того, чтобы иметь проблему намного позже и не найти его).

1
ответ дан 24 November 2019 в 01:18
поделиться

Строго с логической точки зрения, необходимо думать, что < count было бы более эффективным, чем <= count по точной причине, которая <= будет тестировать на равенство также.

0
ответ дан 24 November 2019 в 01:18
поделиться

Я думаю или в порядке, но когда Вы выбрали, придерживайтесь один или другой. Если Вы привыкли использовать < =, затем попытайтесь не использовать < и наоборот.

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

0
ответ дан 24 November 2019 в 01:18
поделиться

'<'; и '< =', операторы являются точно той же стоимостью производительности.

'<'; оператор является стандартным и более легким для чтения в основанном на нуле цикле.

Используя ++ я вместо я ++ улучшаю производительность в C++, но не в C# - я не знаю о Java.

1
ответ дан 24 November 2019 в 01:18
поделиться

Отличный вопрос. Мой ответ: используйте тип A ('<')

    • Вы ясно понимаете, сколько у вас есть итераций (7).
    • Разница между двумя конечными точками является ширина диапазона
    • , меньшего количества символов делает его более читаемым
    • , у вас чаще всего имеют общее количество элементов I , а не Индекс последнего элемента Так что равномерность важно.

    Другая проблема со всей всей конструкцией. I появляется 3 раза в нем, поэтому он может быть неправильно. Конструкция для петли говорит Как сделать вместо Что делать . Я предлагаю принимать это:

    Boost_Foreach (I, IntegerInterInterval (0,7))

    Это более четкое, компилируется для Exaclty одинаковых инструкций ASM и т. Д. Спросите меня код InteGerInterVal, если хотите.

1
ответ дан 24 November 2019 в 01:18
поделиться

Для некоторых языков/технологий как.NET с помощью.Size или.Length или размер () / длина () плохая идея, это доступы, что свойство каждый раз, когда это выполняет итерации, так присвоил его переменной, имеет немного меньше хита производительности.

0
ответ дан 24 November 2019 в 01:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: