Я читаю boost/asio/coroutine.hpp
и не могу понять реализацию BOOST_ASIO_CORO_REENTER и BOOST_ASIO_CORO_YIELD. Развернутая форма
reenter (this) {
yield ..
yield ..
}
вроде бы переплетены switch / if / for операторы. Мне интересно, почему это действительный код C? Я написал нечто подобное (показано ниже) и обнаружил, что оно компилируется с использованием gcc.
int main() {
int a = 1;
switch (a)
case 0: if (1) a = 2;
else case 1: for (;;) {
case 3:
break;
}
return 0;
}
Это некая уловка устройства Даффа. — person PeopleMoutainPeopleSea schedule 06.01.2020
Если вы используете boost, значит, вы пишете C ++, а не C. Итак, вы должны спросить, почему это действительный C ++, а не почему он действителен C (даже если ответы, вероятно, будут очень похожими). — person PeopleMoutainPeopleSea schedule 06.01.2020
Хотите добавить часть исходного кода? — person PeopleMoutainPeopleSea schedule 06.01.2020
оператор switch с чередованием do-while, Как работает устройство Даффа? — person PeopleMoutainPeopleSea schedule 06.01.2020
Это не имеет ничего общего с boost-asio. Это вопрос синтаксиса. Не ставьте теги без разбора. — person PeopleMoutainPeopleSea schedule 06.01.2020
Синтаксически тело переключателя — это просто оператор (обычно, но не обязательно составной оператор).
6.8:
который может быть помечен как 6.8.1:
Пример:
Если это составной оператор, то рекурсивно можно пометить каждое подвыложение. Пример:
Синтаксис обрабатывает _5 _ / _ 6_-меток и обычные метки одинаково, только семантическая проверка проверяет, что _7 _ / _ 8_-меток находятся внутри
switch
.С точки зрения реализации все компилируется в (плоскую) сборку.
E.g.
сплющен в (псевдосборка)
и нет причин, по которым что-либо в таком плоском коде нельзя было пометить.
_12 _ / _ 13_ метки также похожи на обычные метки, за исключением того, что они также используются (чаще всего) в вычисляемом прыжке.
Причина в том, что операторы переключения не являются структурированными операторами потока управления. Вместо этого их следует рассматривать как синтаксический сахар для статической отправки. Dispatch означает, что поток управления перенаправляется, а static означает, что компилятор знает, куда он перенаправлен.
Итак, ваш код
будет скомпилирован во что-то примерно эквивалентное
где
dispatch
— это функция, которую компилятор запускает для выдачи машинного кода, необходимого для статической отправки. Поскольку все значения отправки являются константами, а все цели отправки известны компилятору, он может генерировать очень эффективный машинный код.Что касается того, почему это законно, я предполагаю, что причина в том, что нет особых причин, по которым это незаконно. Как показано, операторы
case
— это просто метки goto, поэтому их можно размещать где угодно.