Подтвердить что ты не робот

Проницательность в том, как вещи печатаются на экране (cout, printf) и происхождение действительно сложных вещей, которые я, похоже, не могу найти в учебниках

Я всегда удивлялся этому и до сих пор не нашел ответа. Всякий раз, когда мы используем "cout" или "printf", как именно это напечатано на экране?. Как текст выходит так, как он... (возможно, довольно неопределенный вопрос здесь, плохо работайте с тем, что вы мне даете.). Итак, в основном, как эти функции выполняются?.. это сборка?, если так, где это начинается?. Это вызывает больше вопросов, например, как они создали функции openGl/directx.

сломайте его, люди сломают его.:)

4b9b3361

Ответ 1

Здесь один сценарий с сокращениями:

  • printf или cout поместите символы в буфер в адресное пространство программы пользователя.
  • В конце концов буфер заполняется, или, возможно, printf просит освободить буфер раньше. В любом случае библиотека ввода-вывода вызывает операционную систему, которая копирует содержимое буфера в собственное пространство.
  • Предполагая, что выходной файл привязан к терминалу, операционная система доставляет символы в приложение терминала.
  • Приложение терминала решает, что для каждого символа в буфере ему нужно нарисовать пиксели на экране.
  • Приложение терминала устанавливает инструкции по рисованию в пикселях и просит диспетчера окон сделать это от его имени. (В настоящее время в Unix это обычно X-сервер.)
  • Диспетчер окон принимает пиксели. Если окно действительно отображается на экране, диспетчер окон затем обновляет буфер (называемый буфером кадров), который содержит видимые пиксели. Менеджер окон может затем уведомить операционную систему, или, скорее, оконный менеджер находится в сговоре с операционной системой, и они используют одну и ту же память.
  • В следующий раз, когда экран будет обновлен, аппаратное обеспечение увидит новые биты в буфере кадров и покрасит экран по-разному.
  • Voil & agrave;! На экране есть символы.

Удивительно, что медведь танцует вообще.

Ответ 2

Итак, в основном, как эти функции выполняются?.. это сборка?, если так, где это начинается?. Это вызывает больше вопросов, например, как они сделали функции openGl/directx.

Эти функции могут быть сборкой или C, это не сильно меняет (и, в любом случае, вы можете делать на C практически все, что вы можете сделать в сборке.) Магия в конечном итоге происходит на интерфейсе программного и аппаратного обеспечения - то, как вы добираетесь от printf и cout <<, может быть таким же тривиальным, как несколько операций с указателем (см. пример 286 ниже, или читать далее cprintf дальше), или сложнее, чем проходить несколько уровней разнообразных системных вызовов, возможно даже переходящих по сетям, прежде чем в конечном итоге нанести удар по вашему оборудованию дисплея.

Представьте следующие сценарии:

  • Я выкапываю свои старые 286 из-под пыли и запускаю MS-DOS; Я компилирую и запускаю следующую программу в реальном режиме:

    void main(void) {
      far long* pTextBuf = (far long*)0xb8000L;
      /* Poor man gotoxy+cprintf imitation -- display "C:" (0x43,0x3a) in
         silver-on-black letters in the top-left corner of the screen */
      *pTextBuf = 0x073a0743L;
    }
    
  • Я подключаюсь к моему ноутбуку Windows HyperTerminal к своему серийному порту, который подключен кабелем к задней части окна SUN, через который я могу получить доступ к консоли консоли SUN. С этой консоли я ssh в другой блок в сети, где я запускаю свою программу, которая делает printf, передает свой вывод через more, Информация printf прошла через трубу через more, а затем через псевдослучай SSH через сеть в мой блок SUN, оттуда через последовательный кабель на моем ноутбуке, через функции вывода текста Windows GDI, прежде чем, наконец, появиться на моем экране.

Добавляем более подробно к норманнскому ответу, надеюсь, больше в направлении вашего оригинального вопроса:

  • printf и cout << обычно выполняют записи в stdout - обычно буферизованные записи, но это не всегда так
    • в тот же день различные производители компиляторов (Borland, Microsoft), особенно в DOS, предоставили вам такие функции, как cprintf, который писал непосредственно в видеопамять без каких-либо системных вызовов, memcpy -style (см. мой пример 286 выше) - подробнее об этом ниже
  • запись в stdout является системным вызовом, будь то write под * nix, WriteFile или WriteConsole под Windows, INT 21, 9 под DOS и т.д.
  • преимущество прохождения абстракции stdout заключается в том, что он позволяет операционной системе выполнять некоторую внутреннюю сантехнику и выполнять перенаправление (будь то дескриптор tty, в канал, в файл, к последовательному порту, к другой машине через разъем и т.д.),
    • он также косвенно позволяет сосуществовать несколько приложений stdout на одном экране, например. в разных окнах - что-то, что было бы намного сложнее сделать, если бы каждое приложение пыталось напрямую писать в видеопамять (например, cprintf на DOS), а не то, что сегодня можно назвать истинным или полезным многозадачным операционным система).
  • графическое приложение, например ваше приложение приложения консоли rxvt, клиент PuTTY telnet/ssh, консоль Windows и т.д.:
    • прочитайте ваше приложение stdout:
      • из дескриптора tty (или эквивалента) в случае rxvt или консоли Windows
      • из последовательного порта, если вы используете что-то вроде Realterm для подключения со встроенной системой или к старой консоли консоли SUN.
      • из сокета, если вы используете PuTTY в качестве клиента telnet
    • отображает информацию графически, пиксель за пикселем, в контекст буфера/устройства окна графического приложения /etc.
      • это обычно выполняется с помощью еще одного уровня абстракции и системных вызовов (таких как GDI, OpenGL и т.д.).
      • информация о пикселях в конечном итоге заканчивается в линейном буфере кадров, то есть в выделенном диапазоне памяти (еще в дни 8-мегагерцовых процессоров, задолго до AGP эта область может находиться в системной ОЗУ, в настоящее время она может быть мегабайтами и мегабайтами двухпортовой ОЗУ на самой видеокарте )
      • видеокарта (то, что раньше называлось RAMDAC), будет периодически читать буферную память фрейма (например, 60 раз в секунду, когда ваш адаптер VGA был установлен на 60 Гц), scanline после scanline (возможно, используя palette поиск тоже ) и передать его на дисплей в виде аналоговых или цифровых электрических сигналов.
  • в тот же день, или даже сегодня, когда вы загружаете свой * nix-бокс в однопользовательском режиме или выходите в полноэкранном режиме в консоль Windows, ваш графический адаптер фактически находится в текстовый режим
    • вместо буфера фреймового кадра, один (будь то реализация cprintf или ОС) записывает в гораздо меньшие 80x25 или 80x50 и т.д. text buffer, где (например, в случае VGA) требуется только два байта для кодирования каждого значения символа, такого как A или или (1 байт) а также его цветовые атрибуты (1 байт), то есть его передний план (4 бита или 3 бита + бит яркости) и цвета фона (4 бита или 3 бита + мигающий бит).
    • для каждого пикселя на каждой строке сканирования, RAMDAC:
      • будет отслеживать, какой текстовый столбец и какая текстовая строка принадлежит пикселю
      • будет искать значение символа столбца/строки и атрибуты
      • будет выглядеть символьное значение в определение простого растрового шрифта
      • будет видеть, должен ли отображаемый пиксель в определении растрового изображения глифа символьного значения быть установлен на передний план или фон, а какой цвет будет основан на символьном атрибуте в этой позиции.
      • возможно флип переднего плана и фона на четные секунды, если бит бит был установлен или курсор отображается и находится в текущей позиции
      • нарисовать пиксель

Начните с История видеокарты и GPU страницы в Википедии для более глубокого изучения того, как мы попали туда, где мы находимся сегодня.

Также смотрите Как работают графические процессоры и Как работают графические карты.

Ответ 3

Ну, они проходят кучу библиотечных функций и, в конечном итоге, вызывают системный вызов write(), который отправляет данные в соответствующий файловый дескриптор, а затем вызывает его при вызове read() эмулятор терминала (или командная оболочка окна, если это Windows). Терминал/оболочка приводит к тому, что данные должны быть нарисованы на экране, возможно, путем объединения системных вызовов, чтобы отправить их в графическую систему.

Терминология Windows и Unix/Linux совершенно иная, особенно концепция оболочки вовсе не одна и та же. Но использование вызовов read() и write() в обоих случаях довольно схож.

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

Ответ 4

Взломайте исходный код glibc и убедитесь сами.

Короткий ответ, много кода C, иногда посыпанный каким-то ассемблером.

Ответ 5

Магия действительно происходит в драйвере устройства. ОС представляет собой интерфейс для программирования программистов приложений. Это немного массируется (например, забуферировано), а затем отправляется на устройство. Затем устройство принимает общее представление и преобразует его в сигналы, которые может понять конкретное устройство. Таким образом, ASCII отображается в разумном формате somme на консоли или в файле PDF или на принтере или на диске в форме, подходящей для этого устройства. Попробуйте что-то другое, кроме ASCII (или UTF8), которое драйвер не понимает, и вы увидите, о чем я говорю.

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

Каждый драйвер устройства отличается. Но каждый из них одинаково с точки зрения того, как они взаимодействуют с ОС, по крайней мере для каждого класса устройств (диск, сетевой адаптер, клавиатура и т.д.).