Заявление о переключении — Пересмотр синтаксиса устройства Даффа — Это законно C / C ++?

Только прошлой ночью я столкнулся с любопытным Устройство Даффа в первый раз. Я читал об этом, и я не думаю, что это так сложно понять. Что мне интересно, так это странный синтаксис (из Википедии):

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: Изменен пересмотренный пример кода для учета неверных значений счетчика.

8

Решение

Если взглянуть на стандарт C ++ 11, то часть кода, о которой вы спрашиваете, будет разрешена. Ты это пробовал?

Правило, которое я вижу, наиболее применимо:

Замечания: Обычно подотчет, который является предметом переключения, является составным и case а также default метки появляются в инструкциях верхнего уровня, содержащихся в (составном) подзаголовке, но это не обязательно.

На самом деле это означает, что вы можете избавиться от брекетов вокруг dowhile, и писать

  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);
8

Другие решения

Код, безусловно, является законным: нет никаких требований к блокам и / или циклам. Стоит отметить, однако, что 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 цикл, кажется, приведенный выше код более естественно иметь дело с граничным условием.

1

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

РЕДАКТИРОВАТЬ: Нет требования, чтобы тело оператора switch начиналось с метки, любой код допустим. Тем не менее, нет никакого пути в него из самого оператора switch, поэтому, если это не цикл или простая метка, код будет недоступен.

Еще одна интересная вещь с swtich Утверждение, что фигурные скобки являются необязательными. Однако в этом случае допускается только одна метка:

  switch (i)
case 5: printf("High five\n");
1
По вопросам рекламы [email protected]