Только прошлой ночью я столкнулся с любопытным Устройство Даффа в первый раз. Я читал об этом, и я не думаю, что это так сложно понять. Что мне интересно, так это странный синтаксис (из Википедии):
register short *to, *from;
register int count;
{
register int n = (count + 7) / 8;
switch(count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0);
}
}
Я читал стандартное определение C ++ заявление о переключении (пожалуйста, дайте мне знать, если это устарело, я не знаком с Open-Std.org). Насколько я понимаю, операторы case — это просто упрощенные операторы перехода для использования оператором switch.
Сам коммутатор полностью игнорирует вложенный do-while, а цикл игнорирует операторы case. Поскольку переключатель переходит внутрь цикла, цикл выполняется. Переключатель предназначен для покрытия остатка (от деления на 8), а цикл обрабатывает часть, которая делится равномерно. Это все имеет смысл.
Мой вопрос тогда почему неуклюжий синтаксис? Мне приходит в голову, что цикл может быть написан так, что все операторы case содержатся внутри, да? Я не вижу ничего в стандарте, который запрещает такое поведение, и он правильно компилируется в GCC 4.7, поэтому считается ли следующее законным?
register short *to, *from;
register int count;
{
register int n = (count + 7) / 8;
switch (count <= 0 ? 8 : count % 8)
{
do
{
case 0: *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
default: ; // invalid count, suppress warning, etc.
} while(--n > 0);
}
}
Для меня это делает смысл кода намного понятнее. Спасибо за любые отзывы. 😉
Редактировать: Как отмечено ниже, исходный код был написан для C и имел неявный int для подсчитывать а также N переменные. Так как я пометил это C ++, я изменил это.
Изменить 2: Изменен пересмотренный пример кода для учета неверных значений счетчика.
Если взглянуть на стандарт C ++ 11, то часть кода, о которой вы спрашиваете, будет разрешена. Ты это пробовал?
Правило, которое я вижу, наиболее применимо:
Замечания: Обычно подотчет, который является предметом переключения, является составным и
case
а такжеdefault
метки появляются в инструкциях верхнего уровня, содержащихся в (составном) подзаголовке, но это не обязательно.
На самом деле это означает, что вы можете избавиться от брекетов вокруг do
—while
, и писать
int n = (count + 7) / 8;
switch (count % 8) do
{
case 0: *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0);
Тем не менее, эта строка НЕ является допустимой C ++:
register n = (count + 7) / 8;
C ++ не позволяет default-int, тип переменной должен быть указан или выведен.
О, вот, исправьте количество итераций, не нарушая форматирование:
int n = 1 + count / 8;
switch (count % 8) do
{
*to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
case 0: ;
} while(--n > 0);
Код, безусловно, является законным: нет никаких требований к блокам и / или циклам. Стоит отметить, однако, что count == 0
неправильно обрабатывается вышеуказанным циклом. Это, однако, правильно обрабатывается этим:
int count = atoi(ac == 1? "1": av[1]);
switch (count % 4)
{
case 0: while (0 < count) { std::cout << "0\n";
case 3: std::cout << "3\n";
case 2: std::cout << "2\n";
case 1: std::cout << "1\n";
count -= 4;
}
}
Ввод case 0
Метка внутри цикла также неправильно выполняла бы вложенные операторы. Хотя я видел устройство Даффа, всегда использующее do-while
цикл, кажется, приведенный выше код более естественно иметь дело с граничным условием.
Да, это законно. Ярлыки switch
заявление обычно написано на том же уровне, что и switch
заявление. Тем не менее, законно писать их в составных утверждениях, например, в середине петли.
РЕДАКТИРОВАТЬ: Нет требования, чтобы тело оператора switch начиналось с метки, любой код допустим. Тем не менее, нет никакого пути в него из самого оператора switch, поэтому, если это не цикл или простая метка, код будет недоступен.
Еще одна интересная вещь с swtich
Утверждение, что фигурные скобки являются необязательными. Однако в этом случае допускается только одна метка:
switch (i)
case 5: printf("High five\n");