c++ - reales - Una idea de cómo se imprimen las cosas en la pantalla(cout, printf) y el origen de cosas realmente complejas que parece que no puedo encontrar en los libros de texto
cosas raras encontradas en el mundo (5)
Entonces, básicamente, ¿cómo se hacen esas funciones? ... ¿es un montaje ?, si es así, ¿dónde comienza eso? Esto genera más preguntas, como cómo han hecho las funciones openGl / directx.
Esas funciones pueden ser ensambladas o C, no cambia mucho (y, de todos modos, puede hacer en C prácticamente todo lo que puede hacer en ensamblaje). La magia finalmente ocurre en la interfaz de software y hardware : cómo se llega allí de printf
y cout <<
puede ser tan trivial como algunas operaciones de puntero (vea el ejemplo 286 a continuación, o lea sobre cprintf
más abajo), o tan complejo como atravesar múltiples capas de diversas llamadas al sistema, posiblemente incluso pasando por redes, antes eventualmente golpeando su hardware de exhibición.
Imagine los siguientes escenarios :
Desenterro mi viejo 286 de debajo del polvo y enciendo MS-DOS; Compilo y ejecuto el siguiente programa en modo real :
void main(void) { far long* pTextBuf = (far long*)0xb8000L; /* Poor man''s gotoxy+cprintf imitation -- display "C:" (0x43,0x3a) in silver-on-black letters in the top-left corner of the screen */ *pTextBuf = 0x073a0743L; }
Me estoy conectando con el HyperTerminal de Windows de mi computadora portátil a mi puerto serie, que está conectado con un cable en la parte posterior de una caja de SUN, a través del cual puedo acceder a la consola de mi SUN box. Desde esa consola, me conecto con otra caja en la red, donde ejecuto mi programa, que
printf
, produciendomore
. La información deprintf
ha viajado a través de una tuberíamore
, luego a través de una pseudo-tty SSH a través de la red a mi SUN box, desde allí a través del cable serie a mi laptop, a través de las funciones de dibujo de texto GDI de Windows antes de aparecer finalmente en mi pantalla.
Agregando más detalles a la respuesta de Norman , con suerte más en la dirección de su pregunta original:
-
printf
ycout <<
normalmente realizan escrituras enstdout
, generalmente grabaciones en búfer, pero ese no siempre ha sido el caso- En el pasado, varios proveedores de compiladores (Borland, Microsoft), especialmente en DOS, le proporcionaban funciones como
cprintf
, que escribía directamente a la memoria de video sin hacer ninguna llamada al sistema,memcpy
(vea mi ejemplo 286) más en ese más abajo
- En el pasado, varios proveedores de compiladores (Borland, Microsoft), especialmente en DOS, le proporcionaban funciones como
- escribir en
stdout
es una llamada al sistema, ya seawrite
bajo * nix,WriteFile
oWriteConsole
en Windows, INT 21, 9 en DOS, etc. - La ventaja de pasar por la abstracción
stdout
es que permite que el sistema operativo haga algunas conexiones internas y realice una redirección (ya sea a un descriptor tty, a una tubería, a un archivo, a un puerto serie, a otra máquina a través de un zócalo etc.)- también indirectamente hace posible que múltiples
stdout
s de aplicaciones coexistan en la misma pantalla, por ejemplo, en diferentes ventanas, algo que sería mucho más difícil de hacer si cada aplicación tratara de escribir directamente en la memoria de video por sí mismo (comocprintf
did en DOS, no es lo que hoy llamaríamos un sistema operativo multitarea verdadero o utilizable).
- también indirectamente hace posible que múltiples
- hoy en día, una aplicación gráfica como su aplicación de ventana de consola
rxvt
, cliente PuTTY telnet / ssh, consola de Windows, etc.:- lea la
stdout
su aplicación:- desde un descriptor tty (o equivalente) en el caso de
rxvt
o de la consola de Windows - desde un puerto serie si está utilizando algo como Realterm para conectarse a un sistema integrado o a una consola de cuadro SUN anterior
- desde un socket si está utilizando PuTTY como cliente de telnet
- desde un descriptor tty (o equivalente) en el caso de
- muestre la información renderándola gráficamente, píxel por píxel , en el buffer de ventana de la aplicación gráfica / contexto del dispositivo / etc.
- esto normalmente se realiza a través de otra capa de abstracción y llamadas al sistema (como GDI, OpenGL, etc.)
- la información de píxeles finalmente termina en un búfer de cuadros lineal , es decir, un rango de memoria dedicado (en los tiempos de las CPU de 8MHz, mucho antes de AGP, esta área podría residir en la RAM del sistema, hoy en día podría ser megabytes y megabytes de dual- puerto RAM en la tarjeta de video en sí)
- la tarjeta de video (lo que solía llamarse RAMDAC ), leería periódicamente el rango de la memoria intermedia (por ejemplo, 60 veces por segundo cuando su adaptador VGA estaba configurado para 60Hz), escanea la línea de escaneo (posiblemente también realiza búsquedas de palette ) y transmite a la pantalla como señales eléctricas analógicas o digitales
- lea la
- de vuelta en el día, o incluso hoy cuando arranca su * nix box en modo monousuario o va a pantalla completa en una consola de Windows, su adaptador de gráficos está realmente en modo texto
- en lugar de un buffer de trama liner, uno (ya sea la implementación
cprintf
o el SO) escribe en la matriz de buffer de texto mucho más pequeña de 80x25 o 80x50 etc. , donde (por ejemplo, en el caso de VGA) solo se necesitan dos bytes para codificar cada carácter valor comoA
o▒
o♣
(1 byte), así como sus atributos de color (1 byte), es decir, su primer plano (4 bits, o 3 bits + bit de brillo) y colores de fondo (4 bits o 3 bits + bit de parpadeo) - para cada píxel en cada línea de exploración, la RAMDAC:
- haría un seguimiento de qué columna de texto y qué fila de texto ese píxel pertenece a
- buscaría los atributos y el valor del carácter de esa columna / fila
- vería el valor del carácter frente a una definición de fuente de mapa de bits simple
- vería si el píxel que se representa, en la definición del mapa de bits del glifo del valor del personaje, debe establecerse en primer plano o en segundo plano, y de qué color se basaría en el atributo del carácter en esa posición
- posiblemente voltee el primer plano y el fondo incluso en segundos si el bit de parpadeo se configuró o el cursor se muestra y está en la posición actual
- dibuja el pixel
- en lugar de un buffer de trama liner, uno (ya sea la implementación
Comience en la historia de las tarjetas de video y las páginas de la GPU en Wikipedia para obtener una visión más detallada de cómo llegamos a donde estamos hoy.
También vea cómo funcionan las GPU y cómo funcionan las tarjetas gráficas .
Siempre me he preguntado esto, y todavía no he encontrado la respuesta. Siempre que usemos "cout" o "printf", ¿cómo se imprime exactamente en la pantalla ?. ¿Cómo sale el texto como lo hace ... (probablemente una pregunta bastante vaga, trabajo mal con lo que sea que me des). Entonces, básicamente, ¿cómo se hacen esas funciones? ... ¿es un montaje ?, si es así, ¿dónde comienza eso? Esto genera más preguntas, como cómo han hecho las funciones openGl / directx.
descomponerlo, la gente lo descompone :)
Aquí hay un escenario, con abreviaturas:
-
printf
ocout
colocan caracteres en un búfer en el espacio de direcciones del programa de usuario. - Eventualmente, el buffer se llena, o quizás
printf
pida que el buffer se vacíe temprano. De cualquier manera, la biblioteca de E / S llama al sistema operativo, que copia el contenido del búfer a su propio espacio. - Suponiendo que el archivo de salida está vinculado a un terminal, el sistema operativo entrega los caracteres a la aplicación del terminal.
- La aplicación de terminal decide que para cada carácter en el búfer, necesita pintar píxeles en la pantalla.
- La aplicación del terminal establece las instrucciones de pintura de píxeles y le pide a un administrador de ventanas que haga esto en su nombre. (En Unix en la actualidad, este suele ser un servidor X.)
- El administrador de ventanas toma los píxeles. Si la ventana es realmente visible en la pantalla, el administrador de ventanas luego actualiza un búfer (llamado el búfer de cuadros ) que contiene los píxeles visibles. El administrador de ventanas puede entonces notificar al sistema operativo, o más probablemente, el administrador de ventanas está en connivencia con el sistema operativo y comparten la misma memoria.
- La próxima vez que se actualiza la pantalla, el hardware ve los nuevos bits en el búfer de cuadros y pinta la pantalla de manera diferente.
- Voilà! Tienes personajes en la pantalla.
Es increíble que el oso baila en absoluto.
Bueno, pasan por un conjunto de funciones de biblioteca, y finalmente terminan llamando a una llamada al sistema write (), que envía los datos al descriptor de archivo apropiado, lo que hace que aparezca en una llamada de lectura () en el emulador de terminal (o el shell de la ventana de comandos, si esto es Windows). El terminal / shell hace que los datos se pinten en la pantalla, probablemente a través de varias llamadas al sistema para enviarlo al sistema de gráficos.
La terminología de Windows y Unix / Linux es bastante diferente, especialmente el concepto de shell no es para nada lo mismo en cada uno. Pero el uso de las llamadas de lectura () y de escritura () es bastante similar en ambos casos.
Las llamadas al sistema son funciones especiales que hacen que el kernel haga cosas específicas; cómo se implementan es bastante mágico, y depende mucho del tipo de procesador que tengas, pero generalmente es causando algún tipo de error de procesador recuperable que el kernel tiene que ordenar.
La magia realmente sucede en el controlador del dispositivo. El sistema operativo presenta una interfaz para que los programadores de aplicaciones se conecten. Esto se masajea un poco (por ejemplo, en un buffer) y luego se envía al dispositivo. Luego, el dispositivo toma la representación común y la transforma en señales que el dispositivo en particular puede comprender. Por lo tanto, ASCII se muestra en un formato razonable en la consola, o en un archivo PDF, o en una impresora, o en un disco, en la forma adecuada para ese dispositivo. Pruebe con algo que no sea ASCII (o UTF8) que el conductor no comprenda y verá de lo que estoy hablando.
Para cosas que el sistema operativo no puede manejar (tarjetas gráficas especiales, por ejemplo), la aplicación escribe los datos directamente en la memoria del dispositivo. Así es como algo como DirectX funciona (para simplificar drásticamente).
Cada controlador de dispositivo es diferente. Pero cada uno es igual en términos de cómo se interconectan con el SO, al menos para cada clase de dispositivo (disco, NIC, teclado, etc.).