Ответ 1
В этом коде нет указателей и ссылок, поэтому строгие правила псевдонимов даже не входят в изображение. И действительно, автор вызывает точки последовательности, а не строгий псевдоним, чтобы оправдать утверждение, что оно undefined. Однако, похоже, это рассуждение неверно, и фрагмент кода имеет совершенно определенную семантику. Как Prasoon Saurav объясняет более подробно:
(§1.9/15) Вычисления значений операндов оператора секвенируются перед вычислением значения результата оператора.
Поэтому в отношении оператора =
оценка a
и (a >> 16) | (a << 16)
секвенируется перед назначением. Ни один из них не является проблематичным: хотя его части не имеют никакого значения относительно друг друга, не сохраняется запись в a
, которая должна быть упорядочена.
(Технически это поднимает вопрос о том, как побочный эффект присваивания упорядочен по его вычислению значения, но я ничего не мог найти на этом. Предположительно, он где-то в стандарте, но у меня нет копии. Я сильно подозреваю, что он был упорядочен после вычисления значения по причинам в следующем абзаце.)
Вы также можете применить здравый смысл: пишите a
нужно сначала оценить (a >> 16) | (a << 16)
, чтобы написать правильное значение, и, следовательно, оно не может произойти в середине этой оценки. Еще одна проблема со статьей состоит в том, что даже если
uint32_t
swaphalves(uint32_t a)
{
a = (a >> 16) | (a << 16);
return a;
}
было поведение undefined из-за точек последовательности,
uint32_t
swaphalves(uint32_t a)
{
return (a >> 16) | (a << 16);
}
не будет (записи не будут упорядочены), и поэтому гораздо более сложные версии (union, memcpy), которые занимают большую часть остальной части статьи, бессмысленны.