Сначала мы создаем контейнер .Box
и устанавливаем ширину и высоту. Честно говоря, это просто для демо, я установил 80vw и 80vh. И этот контейнер должен быть гибким элементом с ориентацией столбцов flex-flow: column wrap;
. И мы устанавливаем максимальную ширину наибольших блоков (.BoxItem--large { max-width: 80%; height: 100%; }
) на 100% высоты родителей. Он предназначен для переноса других элементов на новую строку / столбец. Поэтому элементы из другого столбца должны заполнять все пространство, поэтому мы устанавливаем .BoxItem--small { max-width: 20%; height: auto; }
- да, 80% + 20% == 100%, что математика. позволяет изменять поведение на экранах с низкой шириной. @media screen and (max-width: 600px) { .Box { flex-flow: column nowrap; } }
нам не нужно обертывать элементы, поэтому просто измените это. После этого мы хотим, чтобы каждый элемент BoxItem
унаследовал ширину родителей. .BoxItem { width: 100%; max-width: 100%; }
max-width: 100%;
для каскадирования, мы не хотим заботиться о некоторых старых правилах, таких как .BoxItem--large { max-width: 80%; }
и .BoxItem--small { max-width: 20%; }
. И установите некоторые изменения порядка.
*,
*:before,
*:after {
box-sizing: inherit;
}
html {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
body {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
background-color: #F72F4E;
overflow: hidden;
}
.Box {
width: 80vw;
height: 80vh;
background-color: rgba(0,0,0,.2);
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-flow: column wrap;
-ms-flex-flow: column wrap;
flex-flow: column wrap;
-webkit-box-align: baseline;
-webkit-align-items: baseline;
-ms-flex-align: baseline;
align-items: baseline;
}
.BoxItem {
background-color: #fff;
border: 1px solid #000;
}
.BoxItem--large {
max-width: 80%;
height: 100%;
}
.BoxItem--small {
max-width: 20%;
height: auto;
}
@media screen and (max-width: 600px) {
.Box {
-webkit-flex-flow: column nowrap;
-ms-flex-flow: column nowrap;
flex-flow: column nowrap;
}
.BoxItem {
width: 100%;
max-width: 100%;
}
.BoxItem--large {
height: auto;
}
.BoxItem--1 {
-webkit-box-ordinal-group: 3;
-webkit-order: 2;
-ms-flex-order: 2;
order: 2;
}
.BoxItem--2 {
-webkit-box-ordinal-group: 2;
-webkit-order: 1;
-ms-flex-order: 1;
order: 1;
}
.BoxItem--3 {
-webkit-box-ordinal-group: 4;
-webkit-order: 3;
-ms-flex-order: 3;
order: 3;
}
}
<div class="Box">
<div class="BoxItem BoxItem--large BoxItem--1">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto omnis rerum ea assumenda velit. Dolores ea unde iste esse illo sit, repellat molestias deleniti, voluptas expedita commodi odio possimus amet?</div>
<div class="BoxItem BoxItem--small BoxItem--2">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto omnis rerum ea assumenda velit.</div>
<div class="BoxItem BoxItem--small BoxItem--3">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto omnis rerum ea assumenda velit.</div>
</div>
Это вызвано комбинацией неопределенного поведения в C и фактом, что код, созданный для процессоров IA-32, имеет 5-битную маску, применяемую к счету сдвига. Это означает, что на процессорах IA-32 диапазон смещения рассчитывается только 0-31. 1
Из Язык программирования C 2
Результат не определен, если правый операнд отрицательный, или больше или равно количеству бит в типе левого выражения.
blockquote>Из IA-32 Руководство разработчика программного обеспечения Intel Architecture 3
8086 не маскирует количество сдвигов. Однако все остальные процессоры IA-32 (начиная с процессора Intel 286) маскируют счетчик сдвига до 5 бит, что приводит к максимальному счету 31. Эта маскировка выполняется во всех режимах работы (включая режим виртуального 8086) до уменьшите максимальное время выполнения инструкций.
blockquote>
1 http://codeyarns.com/2004/12/20/c- shift-operator-mayhem /
2 A7.8 Операторы сдвига, Приложение A. Справочное руководство, Язык программирования C
3 SAL / SAR / SHL / SHR - Shift, глава 4. Справочник по набору инструкций, Руководство разработчика программного обеспечения для архитектуры Intel IA-32
Он работает не так, как ожидалось, потому что вы ожидаете слишком многого.
В случае x86 аппаратное обеспечение не заботится о операциях смены, где счетчик больше, чем размер регистра (см., например, описание инструкции SHL в справочной документации x86 для объяснения).
Стандарт C ++ не хотел налагать дополнительные расходы, рассказывая, что делать в этих случаях потому что сгенерированный код был бы вынужден добавить дополнительные проверки и логику для каждого параметрического сдвига.
С помощью этой свободы разработчики компиляторов могут генерировать только одну инструкцию сборки без каких-либо тестов или ветвей.
Более «полезным» и «логическим» подходом было бы, например, иметь (x << y)
эквивалент (x >> -y)
, а также обработку высоких счетчиков с логическим и последовательным поведением.
Однако это имело бы потребовалось гораздо более медленное обращение для смещения бит, поэтому выбор заключался в том, чтобы делать то, что делает аппаратное обеспечение, оставляя программистам необходимость писать
Учитывая, что в этих случаях разные аппаратные средства делают разные вещи, что стандарт говорит в основном: «Что бы ни случилось, когда вы делаете странные вещи, просто не вините C ++, это ваша вина» переведено в legalese.
shr eax
vs. shr eax,1
, и тот факт, что gcc имел фасет дизайна, в котором shr eax,33
имел бы И непосредственный операнд с 31, чтобы убедиться, что он вписывается в 5-разрядный слот параметра в инструкции , Immediate-mode shr
имеет величину сдвига, закодированную непосредственно в инструкции i>, по крайней мере на x86 и большинстве других архитектур CISC. т. е. вопрос о том, как компилятор выполняет маскировку. ПОДДЕРЖИВАЙТЕ ЦП. Это прекрасное различие, но важное.
– fluffy
13 September 2011 в 23:18
Ответы Lindydancer и 6502 объясняют, почему (на некоторых машинах) это печатается 1
(хотя поведение операции не определено). Я добавляю детали, если они не очевидны.
Я предполагаю, что (как и я) вы запускаете программу на процессоре Intel. GCC генерирует эти инструкции по сборке для операции переключения:
movl $32, %ecx
sall %cl, %eax
В разделе sall
и других операциях смены на стр. 624 в справочном руководстве [* g0] указано:
8086 не маскирует количество сдвигов. Тем не менее, все остальные процессоры Intel Architecture (начиная с процессора Intel 286) маскируют счетчик сдвига до пяти бит, что приводит к максимальному счету 31. Эта маскировка выполняется во всех режимах работы (включая режим виртуального 8086), чтобы уменьшить Максимальное время выполнения команд.
blockquote>Поскольку нижние 5 бит 32 равны нулю, тогда
1 << 32
эквивалентен1 << 0
, который является1
.Экспериментируя с большими числами, мы предсказываем, что
cout << (a << 32) << " " << (a << 33) << " " << (a << 34) << "\n";
будет печатать
1 2 4
, и действительно, это то, что происходит на моей машине.
Поскольку вы смещаете бит int на 32 бита; вы получите: warning C4293: '<<' : shift count negative or too big, undefined behavior
в VS. Это означает, что вы смещаетесь за пределы целого числа, и ответ может быть НИЧЕГО, потому что это неопределенное поведение.
Смещение 32-битной переменной на 32 или более бит является неопределенным поведением и может заставить компилятор заставить демонов вылететь из вашего носа.
Серьезно, большую часть времени вывод будет 0 (если int
составляет 32 бит или меньше), так как вы перемещаете 1 до тех пор, пока он не опустится снова, и останется только 0. Но компилятор может оптимизировать его, чтобы делать все, что ему нравится.
См. Замечательную запись в блоге LLVM Что должен знать каждый программист C о неопределенном поведении , обязательный для каждого разработчика C .
Это неопределенное поведение в соответствии со стандартом C ++:
Значение E1 & lt; E2 - левые сдвинутые позиции E2; освобожденные биты заполняются нулями. Если E1 имеет неподписанный тип, значение результата E1 × 2 ^ E2, приведенное по модулю больше, чем максимальное значение, представляемое в типе результата. В противном случае, если E1 имеет подписанный тип и неотрицательное значение, а E1 × 2 ^ E2 представляется в типе результата, то это результирующее значение; в противном случае поведение не определено.
blockquote>
В C ++ сдвиг только четко определен, если вы смещаете значение меньше шагов, чем размер этого типа. Если int
- 32 бита, то определено только 0 до 31 и включает в себя 31 шаг.
Итак, почему это?
Если вы посмотрите на базовое оборудование, которое выполняет сдвиг, если оно должно смотреть только на младшие пять бит значения (в 32-битном случае), оно может быть реализовано с использованием менее логических ворот, чем если бы он должен был проверять каждый бит значения.
Ответ на вопрос в комментарии
C и C ++ предназначены для работы как можно быстрее на любом доступном оборудовании. Сегодня сгенерированный код - это просто команда «сдвиг», независимо от того, как базовое оборудование обрабатывает значения за пределами указанного диапазона. Если бы языки указали, как должен вести себя сдвиг, сгенерированный мог бы проверить, находится ли счет сдвига в диапазоне до выполнения сдвига. Как правило, это дает три инструкции (сравнение, ветвь, сдвиг). (По общему признанию, в этом случае это не было бы необходимо, поскольку количество сдвигов известно.)
У меня была та же проблема, и это сработало для меня:
f = ((long long) 1 & lt; (i-1));
Где я могу любое целое число больше 32 бит. 1 должен быть 64-битным целым для перехода на работу.
Вы можете попробовать следующее. Это фактически дает выход как 0
после 32
сдвигов влево.
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int a = 1;
a <<= 31;
cout << (a <<= 1);
return 0;
}