1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-27 09:12:07 +01:00
Files
archived-doc-ru/language/operators/bitwise.xml
2024-04-17 02:32:57 +03:00

700 lines
24 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 61374bbe228e8e9c55a24aba59a1e2bb2a871148 Maintainer: sergey Status: ready -->
<!-- Reviewed: no -->
<sect1 xml:id="language.operators.bitwise">
<title>Побитовые операторы</title>
<titleabbrev>Побитовые операторы</titleabbrev>
<simpara>
Побитовые операторы вычисляют и управляют конкретными битами
внутри целого числа.
</simpara>
<table>
<title>Побитовые операторы</title>
<tgroup cols="3">
<thead>
<row>
<entry>Пример</entry>
<entry>Название</entry>
<entry>Результат</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<userinput>$a &amp; $b</userinput>
</entry>
<entry>И</entry>
<entry>
Биты, которые установлены и в переменной <varname>$a</varname>,
и в переменной <varname>$b</varname>.
</entry>
</row>
<row>
<entry>
<userinput>$a | $b</userinput>
</entry>
<entry>Или</entry>
<entry>
Будут заданы биты, которые установлены или в переменной <varname>$a</varname>,
или в переменной <varname>$b</varname>.
</entry>
</row>
<row>
<entry>
<userinput>$a ^ $b</userinput>
</entry>
<entry>Исключающее или</entry>
<entry>
Будут заданы биты, которые установлены либо только в переменной <varname>$a</varname>,
либо только в переменной <varname>$b</varname>, но не в обоих одновременно.
</entry>
</row>
<row>
<entry>
<userinput>~ $a</userinput>
</entry>
<entry>Отрицание</entry>
<entry>
Будут заданы биты, которые не установлены в переменной <varname>$a</varname>, и наоборот.
</entry>
</row>
<row>
<entry>
<userinput>$a &lt;&lt; $b</userinput>
</entry>
<entry>Сдвиг влево</entry>
<entry>
Все биты переменной <varname>$a</varname> сдвигаются влево
на количествво позиций, указанных в переменной <varname>$b</varname>
(каждая позиция предполагает «умножение на 2»)
</entry>
</row>
<row>
<entry>
<userinput>$a &gt;&gt; $b</userinput>
</entry>
<entry>Сдвиг вправо</entry>
<entry>
Все биты переменной <varname>$a</varname> сдвигаются вправо
на количество позиций, указанных в переменной <varname>$b</varname>
(каждая позиция предполагает «деление на 2»)
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Побитовый сдвиг в PHP — это арифметическая операция.
Биты, сдвинутые за границы числа, отбрасываются.
Сдвиг влево дополняет число нулями справа, при этом сдвигая знаковый бит числа
влево, что означает что знак операнда не сохраняется.
Сдвиг вправо сохраняет копию сдвинутого знакового бита слева, что означает
что знак операнда сохраняется.
</para>
<para>
<link linkend="language.operators.precedence">Приоритет операторов</link> изменяют скобками.
Например, выражение <literal>$a &amp; $b == true</literal> сначала проверяет
на равенство, а потом выполняет побитовое «И»; тогда как
выражение <literal>($a &amp; $b) == true</literal> сначала выполняет побитовое «И»,
а потом выполняет проверку на равенство.
</para>
<para>
Если оба операнда для операторов <literal>&amp;</literal>, <literal>|</literal> и
<literal>^</literal> строки, то операция будет проведена с кодами ASCII всех
символов строки и в результате вернёт строку. Во всех остальных случаях, оба операнда
будут <link linkend="language.types.integer.casting">преобразованы к целому</link> и
результатом будет целое число.
</para>
<para>
Если операнд для оператора <literal>~</literal> строка, то операция будет проведена с кодами
ASCII всех символов строки и в результате вернёт строку, иначе как операнд,
так и результат, будут считаться целыми.
</para>
<para>
И операнды, и результат выполнения операторов <literal>&lt;&lt;</literal>
и <literal>&gt;&gt;</literal> рассматриваются как целые числа.
</para>
<para>
<informalexample>
<para>
<literallayout>
В PHP ini-настройка error_reporting использует побитовые значения,
показывая, как практически снимать значения битов.
Чтобы показать все ошибки, кроме замечаний,
инструкции в файле php.ini говорят, что нужно указать:
<userinput>E_ALL &amp; ~E_NOTICE</userinput>
</literallayout>
</para>
<para>
<literallayout>
Начинаем со значения E_ALL:
<computeroutput>00000000000000000111011111111111</computeroutput>
Затем берём значение E_NOTICE...
<computeroutput>00000000000000000000000000001000</computeroutput>
... и инвертируем его оператором <literal>~</literal>:
<computeroutput>11111111111111111111111111110111</computeroutput>
Наконец, указываем побитовое И (&amp;), чтобы установить только те биты,
которые установлены в единицу в обоих значениях:
<computeroutput>00000000000000000111011111110111</computeroutput>
</literallayout>
</para>
<para>
<literallayout>
Другой способ достичь этого — использовать ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR, <literal>^</literal>),
чтобы получить только те биты, которые установлены в единицу
либо только в одном, либо только в другом значении:
<userinput>E_ALL ^ E_NOTICE</userinput>
</literallayout>
</para>
</informalexample>
</para>
<para>
<informalexample>
<para>
<literallayout>
Через настройку опции error_reporting можно также показать,
как устанавливать биты. Показать только ошибки и обрабатываемые ошибки можно
так:
<userinput>E_ERROR | E_RECOVERABLE_ERROR</userinput>
</literallayout>
</para>
<para>
<literallayout>
Здесь процесс сочетает E_ERROR
<computeroutput>00000000000000000000000000000001</computeroutput>
и
<computeroutput>00000000000000000001000000000000</computeroutput>
через оператор ИЛИ (<literal>|</literal>),
чтобы получить биты, установленные хотя бы в одном операнде:
<computeroutput>00000000000000000001000000000001</computeroutput>
</literallayout>
</para>
</informalexample>
</para>
<para>
<example>
<title>Побитовыми операции И, ИЛИ и ИСКЛЮЧАЮЩЕЕ ИЛИ (AND, OR и XOR) над целыми числами</title>
<programlisting role="php">
<![CDATA[
<?php
/*
* Не обращайте внимания на верхний раздел кода,
* это просто форматирование для более ясного вывода.
*/
$format = '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
. ' %3$s (%4$2d = %4$04b)' . "\n";
echo <<<EOH
---------- ----------- -- ----------
результат значение оп тест
---------- ----------- -- ----------
EOH;
/*
* Вот сами примеры.
*/
$values = array(0, 1, 2, 4, 8);
$test = 1 + 4;
echo "\n Побитовое И (AND) \n";
foreach ($values as $value) {
$result = $value & $test;
printf($format, $result, $value, '&', $test);
}
echo "\n Побитовое (включающее) ИЛИ (OR) \n";
foreach ($values as $value) {
$result = $value | $test;
printf($format, $result, $value, '|', $test);
}
echo "\n Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) \n";
foreach ($values as $value) {
$result = $value ^ $test;
printf($format, $result, $value, '^', $test);
}
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
--------- --------- -- ---------
result value op test
--------- --------- -- ---------
Побитовое И
( 0 = 0000) = ( 0 = 0000) & ( 5 = 0101)
( 1 = 0001) = ( 1 = 0001) & ( 5 = 0101)
( 0 = 0000) = ( 2 = 0010) & ( 5 = 0101)
( 4 = 0100) = ( 4 = 0100) & ( 5 = 0101)
( 0 = 0000) = ( 8 = 1000) & ( 5 = 0101)
Побитовое ИЛИ
( 5 = 0101) = ( 0 = 0000) | ( 5 = 0101)
( 5 = 0101) = ( 1 = 0001) | ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) | ( 5 = 0101)
( 5 = 0101) = ( 4 = 0100) | ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) | ( 5 = 0101)
Побитовое исключающее ИЛИ (XOR)
( 5 = 0101) = ( 0 = 0000) ^ ( 5 = 0101)
( 4 = 0100) = ( 1 = 0001) ^ ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) ^ ( 5 = 0101)
( 1 = 0001) = ( 4 = 0100) ^ ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) ^ ( 5 = 0101)
]]>
</screen>
</example>
</para>
<para>
<example>
<title>Побитовая операция ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) над строками</title>
<programlisting role="php">
<![CDATA[
<?php
echo 12 ^ 9; // Выводит '5'
echo "12" ^ "9"; // Выводит символ Backspace (ascii 8)
// ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8
echo "hallo" ^ "hello"; // Выводит ascii-значения #0 #4 #0 #0 #0
// 'a' ^ 'e' = #4
echo 2 ^ "3"; // Выводит 1
// 2 ^ ((int)"3") == 1
echo "2" ^ 3; // Выводит 1
// ((int)"2") ^ 3 == 1
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Сдвиг битов в целых числах</title>
<programlisting role="php">
<![CDATA[
<?php
/*
* Несколько примеров.
*/
echo "\n--- СДВИГ ВПРАВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ (НАТУРАЛЬНЫМИ) ЧИСЛАМИ ---\n";
$val = 4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'слева была вставлена копия знакового бита');
$val = 4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places);
$val = 4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'биты были выдвинуты за правый край');
$val = 4;
$places = 4;
$res = $val >> $places;
p($res, $val, '>>', $places, 'то же, что и выше; нельзя сдвинуть дальше 0');
echo "\n--- СДВИГ ВПРАВО НАД ОТРИЦАТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ ---\n";
$val = -4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'слева была вставлена копия знакового бита');
$val = -4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places, 'биты были выдвинуты за правый край');
$val = -4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'то же, что и выше; нельзя сдвинуть дальше -1');
echo "\n--- СДВИГ ВЛЕВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ (НАТУРАЛЬНЫМИ) ЧИСЛАМИ ---\n";
$val = 4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'правый край был дополнен нулями');
$val = 4;
$places = (PHP_INT_SIZE * 8) - 4;
$res = $val << $places;
p($res, $val, '<<', $places);
$val = 4;
$places = (PHP_INT_SIZE * 8) - 3;
$res = $val << $places;
p($res, $val, '<<', $places, 'знаковые биты были выдвинуты');
$val = 4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'биты были выдвинуты за левый край');
echo "\n--- СДВИГ ВЛЕВО НАД ОТРИЦАТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ ---\n";
$val = -4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'правый край был дополнен нулями');
$val = -4;
$places = (PHP_INT_SIZE * 8) - 3;
$res = $val << $places;
p($res, $val, '<<', $places);
$val = -4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'биты были выдвинуты за левый край, включая знаковый бит');
/*
* Не обращайте внимания на этот нижний раздел кода,
* это просто форматирование для более ясного вывода.
*/
function p($res, $val, $op, $places, $note = '') {
$format = '%0' . (PHP_INT_SIZE * 8) . "b\n";
printf("Выражение: %d = %d %s %d\n", $res, $val, $op, $places);
echo " Десятичный вид:\n";
printf(" val=%d\n", $val);
printf(" res=%d\n", $res);
echo " Двоичный вид:\n";
printf(' val=' . $format, $val);
printf(' res=' . $format, $res);
if ($note) {
echo " ЗАМЕЧАНИЕ: $note\n";
}
echo "\n";
}
?>
]]>
</programlisting>
&example.outputs.32bit;
<screen>
<![CDATA[
--- СДВИГ ВПРАВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ (НАТУРАЛЬНЫМИ) ЧИСЛАМИ ---
Выражение: 2 = 4 >> 1
Десятичный вид:
val=4
res=2
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000000010
ЗАМЕЧАНИЕ: слева была вставлена копия знакового бита
Выражение: 1 = 4 >> 2
Десятичный вид:
val=4
res=1
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000000001
Выражение: 0 = 4 >> 3
Десятичный вид:
val=4
res=0
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
ЗАМЕЧАНИЕ: биты были выдвинуты за правый край
Выражение: 0 = 4 >> 4
Десятичный вид:
val=4
res=0
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше 0
--- СДВИГ ВПРАВО НА ОТРИЦАТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---
Выражение: -2 = -4 >> 1
Десятичный вид:
val=-4
res=-2
Двоичный вид:
val=11111111111111111111111111111100
res=11111111111111111111111111111110
ЗАМЕЧАНИЕ: слева была вставлена копия знакового бита
Выражение: -1 = -4 >> 2
Десятичный вид:
val=-4
res=-1
Двоичный вид:
val=11111111111111111111111111111100
res=11111111111111111111111111111111
ЗАМЕЧАНИЕ: биты были выдвинуты за правый край
Выражение: -1 = -4 >> 3
Десятичный вид:
val=-4
res=-1
Двоичный вид:
val=11111111111111111111111111111100
res=11111111111111111111111111111111
ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше -1
--- СДВИГ ВЛЕВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ (НАТУРАЛЬНЫМИ) ЧИСЛАМИ ---
Выражение: 8 = 4 << 1
Десятичный вид:
val=4
res=8
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000001000
ЗАМЕЧАНИЕ: правый край был дополнен нулями
Выражение: 1073741824 = 4 << 28
Десятичный вид:
val=4
res=1073741824
Двоичный вид:
val=00000000000000000000000000000100
res=01000000000000000000000000000000
Выражение: -2147483648 = 4 << 29
Десятичный вид:
val=4
res=-2147483648
Двоичный вид:
val=00000000000000000000000000000100
res=10000000000000000000000000000000
ЗАМЕЧАНИЕ: знаковые биты были выдвинуты
Выражение: 0 = 4 << 30
Десятичный вид:
val=4
res=0
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
ЗАМЕЧАНИЕ: биты были выдвинуты за левый край
--- СДВИГ ВЛЕВО НАД ОТРИЦАТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ ---
Выражение: -8 = -4 << 1
Десятичный вид:
val=-4
res=-8
Двоичный вид:
val=11111111111111111111111111111100
res=11111111111111111111111111111000
ЗАМЕЧАНИЕ: правый край был дополнен нулями
Выражение: -2147483648 = -4 << 29
Десятичный вид:
val=-4
res=-2147483648
Двоичный вид:
val=11111111111111111111111111111100
res=10000000000000000000000000000000
Выражение: 0 = -4 << 30
Десятичный вид:
val=-4
res=0
Двоичный вид:
val=11111111111111111111111111111100
res=00000000000000000000000000000000
ЗАМЕЧАНИЕ: биты были выдвинуты за левый край, включая знаковый бит
]]>
</screen>
&example.outputs.64bit;
<screen>
<![CDATA[
--- СДВИГ ВПРАВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ (НАТУРАЛЬНЫМИ) ЧИСЛАМИ ---
Выражение: 2 = 4 >> 1
Десятичный вид:
val=4
res=2
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000010
ЗАМЕЧАНИЕ: слева была вставлена копия знакового бита
Выражение: 1 = 4 >> 2
Десятичный вид:
val=4
res=1
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000001
Выражение: 0 = 4 >> 3
Десятичный вид:
val=4
res=0
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
ЗАМЕЧАНИЕ: биты были выдвинуты за правый край
Выражение: 0 = 4 >> 4
Десятичный вид:
val=4
res=0
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше 0
--- СДВИГ ВПРАВО НАД ОТРИЦАТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ ---
Выражение: -2 = -4 >> 1
Десятичный вид:
val=-4
res=-2
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111110
ЗАМЕЧАНИЕ: слева была вставлена копия знакового бита
Выражение: -1 = -4 >> 2
Десятичный вид:
val=-4
res=-1
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111111
ЗАМЕЧАНИЕ: биты были выдвинуты за правый край
Выражение: -1 = -4 >> 3
Десятичный вид:
val=-4
res=-1
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111111
ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше -1
--- СДВИГ ВЛЕВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ (НАТУРАЛЬНЫМИ) ЧИСЛАМИ ---
Выражение: 8 = 4 << 1
Десятичный вид:
val=4
res=8
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000001000
ЗАМЕЧАНИЕ: правый край был дополнен нулями
Выражение: 4611686018427387904 = 4 << 60
Десятичный вид:
val=4
res=4611686018427387904
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0100000000000000000000000000000000000000000000000000000000000000
Выражение: -9223372036854775808 = 4 << 61
Десятичный вид:
val=4
res=-9223372036854775808
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=1000000000000000000000000000000000000000000000000000000000000000
ЗАМЕЧАНИЕ: знаковые биты были выдвинуты
Выражение: 0 = 4 << 62
Десятичный вид:
val=4
res=0
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
ЗАМЕЧАНИЕ: биты были выдвинуты за левый край
--- СДВИГ ВЛЕВО НАД ОТРИЦАТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ ---
Выражение: -8 = -4 << 1
Десятичный вид:
val=-4
res=-8
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111000
ЗАМЕЧАНИЕ: правый край был дополнен нулями
Выражение: -9223372036854775808 = -4 << 61
Десятичный вид:
val=-4
res=-9223372036854775808
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1000000000000000000000000000000000000000000000000000000000000000
Выражение: 0 = -4 << 62
Десятичный вид:
val=-4
res=0
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=0000000000000000000000000000000000000000000000000000000000000000
ЗАМЕЧАНИЕ: биты были выдвинуты за левый край, включая знаковый бит
]]>
</screen>
</example>
</para>
<warning>
<para>
Для побитовых операций над числами, большими чем значение константы <constant>PHP_INT_MAX</constant>,
вызывают функции модуля <link linkend="book.gmp">gmp</link>.
</para>
</warning>
<sect2 role="seealso">
&reftitle.seealso;
<para>
<simplelist>
<member><function>pack</function></member>
<member><function>unpack</function></member>
<member><function>gmp_and</function></member>
<member><function>gmp_or</function></member>
<member><function>gmp_xor</function></member>
<member><function>gmp_testbit</function></member>
<member><function>gmp_clrbit</function></member>
</simplelist>
</para>
</sect2>
</sect1>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->