Что такое порядок байт какой порядок байт в intel
Перейти к содержимому

Что такое порядок байт какой порядок байт в intel

  • автор:

Байты и биты: что нужно знать об их порядке

Байты и биты: что нужно знать об их порядке

В программировании и информатике все данные сохраняются в определенных единицах. Они будут обрабатываться операционной системой особым образом. Зная об измерении данных, а также о так называемом «порядке байт», разработчик сможет оптимизировать функционирование программного продукта.

Далее предстоит разобраться с тем, как обрабатывается информация. Необходимо выяснить возможные варианты и их особенности. Предложенная статья ориентирована на широкую публику. Представленные сведения будут одинаково полезны как программистам, так и системным администраторам. Они также могут показаться интересными «рядовым» пользователям ПК.

Единицы измерения

В компьютерах вся информация измеряется определенным образом. Исторически сложилось так, что минимальной единицей количества данных является бит. Этот термин произошел от английского сокращения bit или binary digit. Дословно соответствующее слово переводится как «двоичная цифра».

Бит – количество информации, которого достаточно для установки различий между двумя явлениями с одинаковой долей вероятности. Им можно интерпретировать одно из двух понятия:

  • 0 – верно, включено, да;
  • 1 – неверно, отключено, нет.

Бит – наименьшая единицы счисления данных. Чаще разработчики пользуются более «крупными» мерами. А именно – байтами. Один байт включает в себя 8 бит.

Байты и биты: что нужно знать об их порядке

Выше можно увидеть таблицу, которая поможет понять, как переводить более крупные единицы измерения имеющиеся информационные единицы.

Об истоках появления байтового порядка

Порядок байтов (или «endian») – важный элемент, оказывающий влияние на работу IT-инженеров и программного обеспечения. Соответствующий компонент не является отдельным термином. Изучая порядок байтов, необходимо обратить внимание на такие определения как «прямой порядок» (big-endian) и «обратный порядок» (little-endian).

Подобные понятия были взяты из книги «Путешествия Гулливера». В ней начинается гражданская война между теми, кто предпочитает разбивать вареные яйца на большом конце (big endians), а также теми, кто предпочитает делать это на маленьком конце (little endians).

В 1980 году некий Денни Коэн, специалист по компьютерам из Израиля, написал статью, в которой он раскрыл вопрос относительно правильного порядка байтов в сообщениях. В своем творении автор связал тематику с «войной», описанной в «Гулливере».

Для описания дискуссий о байтовом порядке (endianness) использовались термины «big endian» и «little endian».

Определение

Современная вычислительная техника и цифровые системы связи представляют чаще всего информацию в виде последовательности. Она формируется из байтов. Если число не может быть реализовано в качестве одного байта, имеет смысл, в каком порядке они записываются на устройстве, а затем передаются по линиям связи. Данный момент сказывается на скорости и качестве обработки материалов.

Обычно выбор порядка записи байтов является произвольным. Он определяется исключительно действующими соглашениями. Порядок байтов – это последовательность, в которой информация будет сохраняться и размещаться в памяти задействованного оборудования.

Актуальность и важность

Сатирическая трактовка в сравнении с произведением «Путешествия Гулливера» big endians (прямой порядок, от старшего к младшему) против little endians (обратного порядка, от младшего к старшему), рассматриваемый вопрос имеет важность для работы с информацией и документами.

Здесь рекомендуется запомнить следующие значимые аспекты:

  1. Блок цифровой информации представляет собой последовательность из нулей и единиц.
  2. Соответствующие единицы и нули начинаются с наименьшего значащего бита (least significant bit, LSb). Заканчиваются они на наибольшем значащем бите (most significant bit, MSb).
  3. 32-разрядный процессор передает 32 бита информации в 32 блока памяти. 64-разрядный – в 64 соответственно.

Чтобы лучше понять, в чем заключается смысл порядка байтов, рекомендуется изучить простейший пример. В нем дан 32-разрядный процессор. Он будет передавать информацию в 32 информационных блока памяти. Им совместно назначается тот или иной адрес. Пример – 0x01. Шина данных в системе создана так, что смешивать LSb и MSb нельзя. Все операции устройства будут использовать 32-битные данные, даже если соответствующие числа могут быть с легкостью реализованы в 16 или 8 битами.

Каждый раз, когда процессор должен получить доступ к сохраненной информации, он просто считает 32 бита из адреса памяти 0x01. Соответствующая концепция является надежной. В порядке байтов нет необходимости.

Рассматриваемый процесс был основан на работе битов. «Байт» не упоминалось. Процессы базируются на 32-битных данных. Делить их на байты не требуется. Реальные цифровые системы, работающие с 32-битными и 64-битными материалами, обычно используют 8-битный сегмент данных. Он известен в информационных технологиях как «байт».

Как на устройстве распределяются байты памяти

Удобное средство демонстрации порядка байтов в действии – это процесс хранения цифровой информации. Пример – используется 8-разрядный микроконтроллер. Все аппаратное обеспечение на устройстве, включая ячейки памяти, предназначаются для работы с 8-битными данными. Адрес 0x00 может включать в себя всего один байт, адрес 0x01 – тоже один и так далее.

Байты и биты: что нужно знать об их порядке

Схема, представленная выше, демонстрирует 11 байтов памяти. Каждая из них хранит всего по 8 бит информации.

Для программирования микроконтроллера, пользуясь компилятором C, порядок байтов будет иметь особую роль. Компилятор должен определить 32-разрядные переменные и хранить их в смежных ячейках памяти. В самом младшем адресе памяти должен хранить наибольший значащий байт (MSB) или наименьший значащий байт (LSB).

Это приводит к тому, что системы могут работать по двум принципам:

  • соблюдая порядок имеющихся байтов big endian – распределение байтов от старшего к младшему;
  • по принципу little endian – от младшего к старшему.

Какой именно вариант правильно использовать, ответить проблематично. Связано это с тем, что любая договоренность может быть одинаково эффективной. Решения между прямым и обратным порядком байтов может базироваться на различных факторах. Пример – на поддержке совместимости с предыдущими версиями процессора.

Кроме прямого и обратного порядка распределения информации есть еще «гибридный» подход. Он не так распространен, но встречается на практике в современных технологиях.

Обратный порядок

Обратный порядок информационных байтов – это принцип «от младшего к старшему». Он называется little endian. Это порядок, обратный «привычному» порядку записи чисел арабскими цифрами. Пример – число 123 было бы записано как 321. Принцип распределения и записи информации здесь будет производиться по правилу «справа–налево».

Обратный порядок информационных байтов является стандартом компьютеров с процессорами архитектуры x86 (Intel и других). Из-за этой особенности концепция иногда называется «интеловским порядком). Современные процессоры x86 дают возможность работать с операндами, рассчитанными на bites:

Соответствующий порядок удобен тем, что при увеличении размера (количества байтов) операнда, значение первого байта остается неизменным.

Кроме архитектуры x86 от Intel соответствующий принцип распределения информации активно используется в VAX-архитектурах (VAX byte order), а также в DEC Alpha и многих других.

Байты и биты: что нужно знать об их порядке

Принцип обратного порядка байтов (little endian) применяется в PCI, USB, таблице разделов GUID. Он является рекомендованным принципом FidoNet. Данное соглашение поддерживает меньше кроссплатформенных протоколов и форматов данных, чем прямой порядок байт.

Прямой порядок

Следующий вариант распределения информации в битовых системах – «напрямую». Он называется прямым порядком байтов, big Indian. Он называется «от старшего к младшему». Является классической формой записи. Порядок следования – «слева–направо». Пример – число «сто двадцать пять» будет записано как 125. В этом же ключе необходимо осуществлять запись битов (байтов) в технической и учебной литературе, если иные особенности операций не указаны.

Принцип записи «всегда вперед» или «от большего к меньшему» – стандарт, который используется в Сети. Он иногда называется «network byte order». Встречается в:

  • протоколах TCP/IP;
  • заголовках пакетов данных;
  • в большинстве протоколов более высокого уровня, которые необходимо использовать поверх TCP/IP.

Такая последовательность байтов в основном задействована в процессорах IBM 360/370/390, SPARC, Motorola 68000. Из-за соответствующей особенности есть второй способ обозначения соглашения – «Motorola byte order).

Правильный принцип использования порядка распределения байтов big endian – сравнение строк (пример – с целыми числами и целочисленными полями-частями большей разрядности, каждое из которых поддерживает сразу несколько символов.

Данное соглашение используется в различных файловых форматах. Примеры – JPEG, FLV, PNG.

Переключаемый

Какой порядок байт в Intel, понятно. Обе рассмотренные концепции примерно равны между собой. Поэтому иногда бывает трудно указать, какой стандарт правильный для поставленной в разработке задачи.

Некоторые процессоры могут функционировать сразу по обеим концепциям. Сюда относят:

  • ARM;
  • PowerPC;
  • DEC Alpha;
  • IA-64;
  • PA-RISC;
  • MIPS.

Последовательность байтов будет выбираться программно во время установки операционной системы. Иногда он настраивается за счет перемычек на материнских платах. Иногда данную концепцию называют big-endian.

Смешанный

Следующий вариант – гибридный или смешанный порядок байтов. Называется middle endian. Он используется при работе с числами, длина которых больше машинного слова. Число будет представлено некоторой последовательностью машинных слов. Они записываются в формате, естественном для выбранной архитектуры. Сами машинные слова следуют в обратном порядке.

Смешанный порядок байтов встречается в процессорах VAX и ARM. В основном концепция задействована при работе с длинными вещественными числами.

Пример

Чтобы лучше понять рассматриваемые процессы, рекомендуется обратить внимание на наглядный пример:

Байты и биты: что нужно знать об их порядке

Здесь описано размещение 4-байтового числа в памяти устройства, доступ к которому поддерживается побайтно и по 32-разрядному слову. Все числа представлены в 16-ричной системе счисления.

Хотите освоить современную IT-специальность? Огромный выбор курсов по востребованным IT-направлениям есть в Otus !

Сокеты Windows. Порядок байтов

В этой статье и двух дополнительных статьях объясняется несколько проблем программирования сокетов Windows. В этой статье рассматриваются упорядочение байтов. Другие проблемы рассматриваются в статьях: сокеты Windows: блокировка и сокеты Windows: преобразование строк.

Если вы используете или извлекаете из класса CAsyncSocket, вам потребуется самостоятельно управлять этими проблемами. При использовании или производных от класса CSocket MFC управляет ими.

Порядок байтов

Разные архитектуры компьютеров иногда хранят данные с помощью разных заказов байтов. Например, компьютеры на основе Intel хранят данные в обратном порядке компьютеров Macintosh (Motorola). Порядок байтов Intel, называемый «little-Endian», также является обратным порядком сети «big-Endian». В следующей таблице описаны эти термины.

Порядок больших и маленьких байтов

Порядок байтов Значение
Big-Endian Самый значительный байт находится в левом конце слова.
Маленький эндиан Самый значительный байт находится в правом конце слова.

Как правило, вам не нужно беспокоиться о преобразовании байтов для данных, которые вы отправляете и получаете по сети, но существуют ситуации, в которых необходимо преобразовать заказы байтов.

Когда необходимо преобразовать заказы байтов

В следующих ситуациях необходимо преобразовать заказы байтов:

  • Вы передаете информацию, которая должна интерпретироваться сетью, а не данные, отправляемые на другой компьютер. Например, можно передать порты и адреса, которые должны понимать сеть.
  • Серверное приложение, с которым вы взаимодействуете, не является приложением MFC (и у вас нет исходного кода). Это вызывает преобразования порядка байтов, если два компьютера не используют одинаковый порядок байтов.

Если вам не нужно преобразовывать заказы байтов

Вы можете избежать работы преобразования заказов байтов в следующих ситуациях:

  • Компьютеры на обоих концах могут не переключать байты, и оба компьютера используют одинаковый порядок байтов.
  • Сервер, с которым вы взаимодействуете, является приложением MFC.
  • У вас есть исходный код для сервера, с которым вы взаимодействуете, поэтому вы можете явно определить, нужно ли преобразовать заказы байтов или нет.
  • Сервер можно перенести в MFC. Это довольно легко сделать, и результат обычно меньше, быстрее кода.

Работая с CAsyncSocket, необходимо самостоятельно управлять любыми необходимыми преобразованиями порядка байтов. Сокеты Windows стандартизуют модель байтового порядка big-Endian и предоставляет функции для преобразования между этим порядком и другими. Однако CArchive, который вы используете с CSocket, использует противоположный порядок («маленький эндиан»), но CArchive заботится о деталях преобразования байтов для вас. Используя этот стандартный порядок в приложениях или с помощью функций преобразования байтов в сокетах Windows, вы можете сделать код более переносимым.

Идеальным вариантом использования сокетов MFC является написание обоих окончаний взаимодействия: использование MFC в обоих концах. Если вы пишете приложение, которое будет взаимодействовать с приложениями, не являющихся MFC, например FTP-сервером, вам, вероятно, потребуется самостоятельно управлять переключениями байтов перед передачей данных в архивный объект, используя подпрограммы преобразования сокетов Windows ntohs, ntohl, htons и htonl. Пример этих функций, используемых в взаимодействии с приложением, отличным от MFC, отображается далее в этой статье.

Если другой конец связи не является приложением MFC, необходимо также избежать потоковой передачи объектов C++, производных от CObject архива, так как получатель не сможет обрабатывать их. См. примечание в сокетах Windows: использование сокетов с архивами.

Дополнительные сведения о заказах байтов см. в спецификации сокетов Windows, доступной в пакете SDK для Windows.

Пример преобразования байтового порядка

В следующем примере показана функция сериализации для CSocket объекта, использующего архив. Он также иллюстрирует использование функций преобразования байтов в API сокетов Windows.

В этом примере представлен сценарий, в котором вы пишете клиент, который взаимодействует с серверным приложением, отличным от MFC, для которого у вас нет доступа к исходному коду. В этом сценарии необходимо предположить, что сервер, отличный от MFC, использует стандартный порядок байтов сети. В отличие от этого, клиентское приложение MFC использует объект с CSocket объектом и CArchive использует CArchive байтовый порядок «little-Endian», противоположность стандарту сети.

Предположим, что сервер, отличный от MFC, с которым планируется взаимодействовать, имеет установленный протокол для пакета сообщений, как показано ниже:

struct Message < long MagicNumber; unsigned short Command; short Param1; long Param2; >; 

В терминах MFC это будет выражено следующим образом:

struct Message < long m_lMagicNumber; short m_nCommand; short m_nParam1; long m_lParam2; void Serialize(CArchive &ar); >; 

В C++, это struct , по сути, то же самое, что и класс. Структура Message может иметь функции-члены, такие как функция-член, объявленная Serialize выше. Функция-член Serialize может выглядеть следующим образом:

void Message::Serialize(CArchive &ar) < if (ar.IsStoring()) < ar else < WORD w; DWORD dw; ar >> dw; m_lMagicNumber = ntohl((long)dw); ar >> w; m_nCommand = ntohs((short)w); ar >> w; m_nParam1 = ntohs((short)w); ar >> dw; m_lParam2 = ntohl((long)dw); > > 

В этом примере вызывается преобразование данных в порядке байтов, так как существует четкое несоответствие между порядком байтов серверного приложения, отличного от MFC, в одном конце и CArchive используемым в клиентском приложении MFC в другом конце. В этом примере показано несколько функций преобразования байтов, предоставляемых сокетами Windows. В следующей таблице описаны эти функции.

Функции преобразования сокетов Windows Byte-Order

Функция Назначение
ntohs Преобразование 16-разрядного количества из сетевого байтового порядка в порядок байтов узла (big-Endian в маленький эндиан).
ntohl Преобразование 32-разрядного количества из байтов сети в порядок байтов узла (big-Endian в маленький эндиан).
Хтоны Преобразование 16-разрядного количества из порядка байтов узла в сетевой порядок байтов (маленький байт в big-Endian).
Htonl Преобразование 32-разрядного количества из порядка байтов узла в сетевой байтовый порядок (маленький байт в big-Endian).

Еще одна точка этого примера заключается в том, что если приложение сокета в другом конце связи — это приложение, отличное от MFC, необходимо избежать выполнения следующих действий:

где pMsg указатель на объект C++, производный от класса CObject . Это приведет к отправке дополнительных сведений MFC, связанных с объектами, и сервер не поймет его, так как это было бы, если бы это было приложение MFC.

Дополнительные сведения см. в разделе:

  • Сокеты Windows. Использование класса CAsyncSocket
  • Сокеты Windows. Фон
  • Сокеты Windows. Сокеты потоков
  • Сокеты Windows. Сокеты датаграмм

Что такое порядок байт какой порядок байт в intel

При работе с данных следует учитывать порядок байтов. В настоящее время распростраенны два порядка байтов: big-endian и little-endian . Порядок big-endian предполагает расположение байтов от старшего к младшему. Порядок little-endian предполагает расположение байтов от младшего к старшему. Например, возьмем шестнадцатеричное число 0x01234567 . Это число состоит из четырех байтов. В архитектурах с big-endian байты этого числа будут расположены следующим образом:

Адрес 0x0000 0x0001 0x0002 0x0003
Значение 01 23 45 67

То есть сначала идет самый старший байт.

В архитектурах с little-endian байты этого числа будут расположены в обратном порядке:

Адрес 0x0000 0x0001 0x0002 0x0003
Значение 67 45 23 01

То есть сначала идет самый младший байт.

Архитектура Intel x86-64 для расположения байтов применяет порядок little-endian . Почему это важно? Возьмем следующую программу под Linux:

global _start section .data number dd 0x01234567 ; 4 байт section .text _start: movzx rdi, byte [number] ; получаем 1-й байт mov rax, 60 syscall

В данном случае в секции данных определено 4-байтное число 0x01234567. Старший байт числа равен «0x01», а самый младший байт числа — «0x67» (103 в десятичной системе). В программе мы получаем первый байт в регистр rdi. Запустим программу:

root@Eugene:~/asm# nasm -f elf64 hello.asm -o hello.o root@Eugene:~/asm# ld -o hello hello.o root@Eugene:~/asm# ./hello root@Eugene:~/asm# echo $? 103 root@Eugene:~/asm#

Мы видим, что самый первый байт равен 103 или 0x67. То есть самый первый байт — это самый младший байт. Соответственно, чтобы получить самый старший байт (четвертый байт), нам надо прибавить смещение в 3 байта:

movzx rdi, byte [number+2]

Но возьмем другую программу (также на Linux):

global _start section .data numbers db 0x01, 0x23, 0x45, 0x67 ; 4 байт section .text _start: movzx rdi, byte [numbers] ; получаем 1-й байт mov rax, 60 syscall

Здесь также в секции данных определены 4 байта, но эти байты представляют массив. Данные массива в памяти расположены в порядке его определения, то есть сначала идет первый байт массива, потом второй и т.д. В итоге в регистр RDI будет помещено число 0х01:

root@Eugene:~/asm# nasm -f elf64 hello.asm -o hello.o root@Eugene:~/asm# ld -o hello hello.o root@Eugene:~/asm# ./hello root@Eugene:~/asm# echo $? 1 root@Eugene:~/asm#

Возьмем более сложный пример:

global _start section .data numbers dw 0x0123, 0x4567 ; 4 байта - каждое число по 2 байта section .text _start: movzx rdi, byte [numbers] ; получаем 1-й байт mov rax, 60 syscall

Опять у нас в секции данных 4 байта, но теперь это массив из двубайтовых чисел (слов). Первое число равно 0x0123 . Но в соответствии с little-endian опять же сначала будет располагаться младший байт числа, а потом старший:

Адрес 0x0000 0x0001
Значение 23 01

Соответственно в регистр RDI будет помещен младший байт числа — 0x23 (число 35 в десятичной системе):

root@Eugene:~/asm# nasm -f elf64 hello.asm -o hello.o root@Eugene:~/asm# ld -o hello hello.o root@Eugene:~/asm# ./hello root@Eugene:~/asm# echo $? 35 root@Eugene:~/asm#

Возьмем четвертую ситуацию:

global _start section .data number db "01234567" ; 8 байт section .text _start: movzx rdi, byte [number] ; получаем 1-й байт mov rax, 60 syscall

Теперь число представлено строкой ASCII. Каждый символ в строке ASCII занимает 1 байт, соответственно строка number занимает 8 байт. Но в плане размещения данных строка символов фактически эквивалентна массиву — в данном случае массиву байт. То есть сначала идет байт (числовой код), который представляет символ «0», далее идет байт символа «1» и так далее. Поэтому в регистре RDI окажется символ 48 — числовой код символа «0»:

root@Eugene:~/asm# nasm -f elf64 hello.asm -o hello.o root@Eugene:~/asm# ld -o hello hello.o root@Eugene:~/asm# ./hello root@Eugene:~/asm# echo $? 48 root@Eugene:~/asm#

Прямой и обратный порядок следования байтов

В процессорах фирмы Intel при выборке и хранении данных в памяти используется так называемый прямой порядок следования байтов (little endian order). Это означает, что младший байт переменной хранится в памяти по меньшему адресу. Оставшиеся байты переменной хранятся в последующих ячейках памяти в порядке возрастания их старшинства. В качестве примера рассмотрим двойное слово, значение которого равно 1234 5678h. Предположим, что оно хранится в памяти со смещением 0. Тогда значение 7 8h будет храниться в первом байте со смещением 0, 56h- во втором байте со смещением 1, 34h — в третьем байте со смещением 2, 12h — в четвертом байте со смещением 3, как показано на рисунке слева.. В некоторых типах процессоров используется обратный

      Виды адресации операндов в памяти

      • Относительнаяпрямаяадресация используется в командах условных переходов для указания относительного адреса перехода. Относительность такого пе- рехода заключается в том, что в поле смещения машинной команды содержится 8-, 16- или 32-разрядное значение, которое в результате работы команды будет складываться с содержимым регистра указателя команд IP/EIP. В результате такого сложения получается адрес, по которому и осуществляется переход.
      • Абсолютнаяпрямаяадресация — в этом случае эффективный адрес является частью машинной команды, но формируется этот адрес только из значения поля смещения в команде. Для формирования физического адреса операнда в памяти процессор складывает это поле со сдвинутым на четыре бита значением сегментного регистра. Однако такая адресация применяется редко — обычно ячейкам в программе присваиваются символические имена. В процессе трансляции ассемблер вычисляет и подставляет значения смещений этих имен в поле смещения формируемой им машинной команды (см. главу 3). В итоге получается, что машинная команда прямо адресует свой операнд, имея, фактически, в одном из своих полей значение эффективного адреса.
      • Косвеннаябазовая (или регистровая) адресация. Эффективный адрес операнда может находиться в любом из регистров общего назначения, кроме SP/ESP и ВР/ЕВР (это специальные регистры для работы с сегментом стека). Синтаксически в команде этот режим адресации выражается заключением имени регистра в квадратные скобки. К примеру, команда mov ax,[ecx] помещает в регистр АХ содержимое слова по адресу сегмента данных со смещением, хранящимся в регистре ЕСХ. Так как содержимое регистра легко изменить в ходе работы программы, данный способ адресации позволяет динамически назначить адрес операнда для некоторой машинной команды. Это очень полезно, например, для организации циклических вычислений и для работы с различными структурами данныхтипа таблиц или массивов.
      • Косвеннаябазоваяадресациясосмещением является дополнением предыдущего вида адресации и предназначена для доступа к данным с известным смещением относительно некоторого базового адреса. Этот вид адресации удобно использовать для доступа к элементам структур данных, когда смещение элементов известно заранее на стадии разработки программы, а базовый (начальный) адрес структуры должен вычисляться динамически на стадии выполнения программы. Модификация содержимого базового регистра позволяет обращаться к одноименным элементам различных экземпляров однотипных структур данных. К примеру, команда mov ax,[edx+3h] пересылает в регистр АХ слово из области памяти по адресу, определяемому содержимым EDX + 3h. Команда mov ax,mas[dx] пересылает в регистр АХ слово по адресу, определяемому содержимым DX плюс значение идентификатора mas (не забывайте, что транслятор присваивает каждому идентификатору значение, равное смещению этого идентификатора относительно начала сегмента данных).
      • Косвеннаяиндекснаяадресациясосмещением очень похожа на косвенную базовую адресацию со смещением. Здесь также для формирования эффективного адреса используется один из регистров общего назначения. Но индексная адресация обладает одной интересной особенностью, которая очень удобна для работы с массивами. Она связана с возможностью так называемого масштабирования содержимого индексного регистра.
      • Косвеннаябазоваяиндекснаяадресация. Ээффективный адрес формируется как сумма содержимого двух регистров общего назначения: базового и индексного. В качестве этих регистров могут применяться любые регистры общего назначения, при этом часто содержимое индексного регистра масштабируется.
      • Косвеннаябазоваяиндекснаяадресациясосмещением. является дополнением косвенной индексной адресации. Эффективный адрес формируется как сумма трех составляющих: содержимого базового регистра, содержимого индексного регистра и значения поля смещения в команде.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *