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

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

#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 ответов

Результаты не имеют смысла.

С аппаратной точки зрения, < = с loopNuumber-1 представит одно дополнительное вычисление, чтобы сделать loopNumber-1 на повторение. Таким образом, я принимаю это < займет меньше времени, если не то же количество времени, чем < =

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

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

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

Никакое различие в скорости, но < более вероятно, будет корректно на языке с массивами на основе 0. Кроме того, если Вы хотите выполнить итерации вниз вместо, можно сказать:

for (i = 7; --i >= 0; ) ...
0
ответ дан 24 November 2019 в 01:19
поделиться

Я следую первому методу, поскольку та идиома часто повторяется.

для (интервал индексируют = 0; индекс < array.length; я ++)

Строка s = oldString.substring (0, numChars);

и т.д.

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

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

Это не должно быть различие в производительности, по крайней мере, с x86 компиляторами. JL и JLE работают то же время, как только я знаю. И что касается удобочитаемости, с помощью "< 7 дюймов для массива семи элементов имеют смысл.

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

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

знать, что 0-> K форма является идиомой C, перенесенной в C# при наличии массивов быть 0 базирующимися. Следуйте за идиомой и не нарушайте принципал наименьшего количества удивления.

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

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

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

Однако (это - просто мысль), удобочитаемости ее, возможно, придется сделать, на основе ли массивы 0 (C#, Java) или на основе 1 (VB.NET). Я говорю это, потому что, когда Вы работаете с массивами на основе 0, Вы входите в мышление, которое 0-6 работало бы 7 раз. Я думаю 0-6, более интуитивно, чем 1-7. С другой стороны я происхожу из C++, Java, фона C#.

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

Я бы сказал, что это должно быть <.

Зачем использовать много слов, когда несколько подойдут. Один тест легче понять, чем два. Следовательно, в будущем легче проводить модульное тестирование и модифицировать.

Разница небольшая? Да. Но зачем добавлять какие-либо сложности, если это не оправдано.

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

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

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