¿Cómo se expande un idioma? [cerrado]

208

Estoy aprendiendo C ++ y acabo de empezar a aprender sobre algunas de las capacidades de Qt para codificar programas GUI. Me hice la siguiente pregunta:

¿Cómo C ++, que anteriormente no tenía sintaxis capaz de pedirle al sistema operativo una ventana o una forma de comunicarse a través de redes (con API que tampoco entiendo completamente, lo admito) de repente obtiene tales capacidades a través de bibliotecas escritas en C ++? Todo me parece terriblemente circular. ¿Qué instrucciones de C ++ podrías encontrar en esas bibliotecas?

Me doy cuenta de que esta pregunta puede parecer trivial para un desarrollador de software experimentado, pero he estado investigando durante horas sin encontrar ninguna respuesta directa. Llegué al punto en que no puedo seguir el tutorial sobre Qt porque la existencia de bibliotecas es incomprensible para mí.

Med Larbi Sentissi
fuente
27
¿Cómo std :: cout incluso dibuja algo en el monitor? ¿O se sienta encima de un compilador que comprende su hardware?
doctorlove
14
Gran pregunta En última instancia, es difícil responder hasta que estudies hardware.
user541686
17
Qt no es una expansión del lenguaje (que requeriría un compilador compatible con Qt). Es simplemente una biblioteca que se agrega a su arsenal. Finalmente, en el nivel más bajo, todas las bibliotecas se comunican con el sistema operativo a través de llamadas al sistema, que son independientes del idioma, pero que dependen mucho del sistema operativo y la arquitectura de la CPU.
DevSolar
8
afaik, C ++ tiene un ensamblaje en línea, que puede hacer casi cualquier cosa
Nombre para mostrar
9
@DevSolar: En realidad, Qt expande el lenguaje con su propio mecanismo de ranura de señal, reflexión y muchas otras características dinámicas. Y esas cosas requieren un compilador (el compilador de metaobjetos) para compilar en código C ++.
Siyuan Ren

Respuestas:

194

Una computadora es como una cebolla, tiene muchas muchas capas, desde el núcleo interno de hardware puro para la capa de aplicación más externa. Cada capa expone partes de sí misma a la siguiente capa externa, de modo que la capa externa puede usar algunas de las funciones de las capas internas.

En el caso de, por ejemplo, Windows, el sistema operativo expone la llamada API WIN32 para aplicaciones que se ejecutan en Windows. La biblioteca Qt usa esa API para proporcionar aplicaciones que usan Qt a su propia API. Utiliza Qt, Qt usa WIN32, WIN32 usa niveles más bajos del sistema operativo Windows, y así sucesivamente hasta que haya señales eléctricas en el hardware.

Algún tipo programador
fuente
56
Nota: Qtaquí proporciona una abstracción de la capa debajo de ella, porque en Linux Qtinvoca la API de Linux y no la API WIN32.
Matthieu M.
55
Probablemente elaboraría un poco más sobre el ejemplo de Qt, que simplemente aparece, como si extendiera sin esfuerzo las capacidades de c ++. Cuando la realidad es, ponen mucho esfuerzo, para hacer una API común, para (discutiblemente) muchos "núcleos de cebolla" diferentes. Son los que proporcionan portabilidad además de backends no estándar no portátiles.
luk32
81
Una computadora es como una cebolla: cortarla te hace llorar, pero después es algo sabrosa.
alecov
3
@ChristopherPfohl Sí, tuve que usarlo ya que no podía entender cómo sería una computadora como una caja de bombones. :)
Algún programador amigo
1
@Celeritas que probablemente dijo el maestro user32.dll, o posiblemente gdi32.dll.
user253751
59

Tienes razón en que, en general, las bibliotecas no pueden hacer nada posible que ya no sea posible.

Pero las bibliotecas no tienen que estar escritas en C ++ para que un programa de C ++ pueda utilizarlas. Incluso si están escritos en C ++, pueden usar internamente otras bibliotecas que no están escritas en C ++. Por lo tanto, el hecho de que C ++ no proporcionara ninguna forma de hacerlo no evita que se agregue, siempre que haya alguna forma de hacerlo fuera de C ++.

En un nivel bastante bajo, algunas funciones llamadas por C ++ (o por C) se escribirán en conjunto, y el conjunto contiene las instrucciones necesarias para hacer lo que no es posible (o no es fácil) en C ++, por ejemplo para llamar Una función del sistema. En ese punto, esa llamada al sistema puede hacer cualquier cosa que su computadora sea capaz de hacer, simplemente porque no hay nada que la detenga.


fuente
¿Quiere decir que las bibliotecas escritas en otros idiomas ya están compiladas con otros compiladores? ¿Y luego tendría que haber algún tipo de archivo de interfaz que vincule cada llamada de función proporcionada a C ++ por la biblioteca a una versión precompilada de la biblioteca? ¿Permitiendo así que el compilador de C ++ sepa en qué traducir esas llamadas?
Med Larbi Sentissi
2
@MedLarbiSentissi 1) No necesariamente otros compiladores. Es posible (y suele ser el caso, a menudo) que un solo compilador sea capaz de compilar múltiples lenguajes, incluido el ensamblado, e incluso puede compilar C ++ con ensamblado en línea. 2) Dependiendo del sistema y compilador específicos, hacer esas funciones invocables desde C ++ puede hacerse con algún tipo de archivo de interfaz, pero ese tipo de archivo de interfaz puede ser un encabezado C (o incluso C ++) directamente utilizable desde C ++.
1
@MedLarbiSentissi: muchas bibliotecas de Windows se compilan en archivos dll que contienen su propia interfaz, así como el código. Puede echar un vistazo a un dll y ver una lista de las funciones que le permite usar. A menudo también vienen con un archivo de encabezado C. Cuando crea su exe, contiene una lista de dlls que necesita ejecutar. Cuando el sistema operativo intenta cargar su exe, también cargará automáticamente esos archivos DLL antes de comenzar la ejecución.
Mooing Duck
8
Esta respuesta parece sugerir que la "magia" se encuentra completamente en otros lenguajes que se llaman, pero en realidad la mayoría del código que constituye la mayoría de los sistemas operativos modernos es C (con solo partes muy vinculadas al hardware o al rendimiento crítico escritas en el ensamblaje), y definitivamente es posible usar C ++ en su lugar. El punto es que no hay "magia", los lenguajes se crean para construir abstracciones tan poderosas, y una vez que puedes interactuar con el hardware, las posibilidades son casi ilimitadas.
Matteo Italia
1
@hvd Creo que todo el conflicto en esta discusión es que usted (y otros) definen C como las características que se le especifican. De hecho, los compiladores agregan mucho más de lo que se especifica, por lo que la pregunta de qué C es un poco trivial de responder. Para mí, lo especial de un lenguaje (por lo tanto, lo que es) es la metaforma para expresar el flujo del programa y las posibilidades de estructurar. Los elementos que están estructurados no son importantes para él, ya que es un código ASM más agradable que los compiladores pueden agregar como lo deseen
LionC
43

C y C ++ tienen 2 propiedades que permiten toda esta extensibilidad de la que habla el OP.

  1. C y C ++ pueden acceder a la memoria
  2. C y C ++ pueden llamar al código de ensamblaje para obtener instrucciones que no estén en el lenguaje C o C ++.

En el kernel o en una plataforma de modo básico no protegido, los periféricos como el puerto serie o la unidad de disco se asignan al mapa de memoria de la misma manera que la RAM. La memoria es una serie de conmutadores y activar los conmutadores del periférico (como un puerto serie o un controlador de disco) hace que su periférico haga cosas útiles.

En un sistema operativo en modo protegido, cuando se quiere acceder al núcleo desde el espacio de usuario (por ejemplo, cuando se escribe en el sistema de archivos o se dibuja un píxel en la pantalla) hay que hacer una llamada al sistema. C no tiene una instrucción para realizar llamadas a un sistema, pero C puede llamar al código del ensamblador que puede activar la llamada correcta al sistema. Esto es lo que permite que el código C se comunique con el núcleo.

Para facilitar la programación de una plataforma en particular, las llamadas al sistema se envuelven en funciones más complejas que pueden realizar alguna función útil dentro del propio programa. Uno es libre de llamar directamente al sistema (usando el ensamblador), pero probablemente sea más fácil hacer uso de una de las funciones de contenedor que proporciona la plataforma.

Hay otro nivel de API que es mucho más útil que una llamada al sistema. Tomemos por ejemplo malloc. Esto no solo llamará al sistema para obtener grandes bloques de memoria, sino que también administrará esta memoria haciendo todo el mantenimiento de libros sobre lo que está sucediendo.

Las API de Win32 envuelven algunas funciones gráficas con un conjunto de widgets de plataforma común. Qt lleva esto un poco más allá al envolver la API Win32 (o X Windows) de una manera multiplataforma.

Básicamente, aunque un compilador de C convierte el código de C en código de máquina y dado que la computadora está diseñada para usar código de máquina, debe esperar que C pueda lograr el recurso compartido de leones o lo que una computadora puede hacer. Todo lo que hacen las bibliotecas de contenedor es hacer el trabajo pesado por usted para que no tenga que hacerlo.

doron
fuente
Advertencia sobre el n. ° 2: C y C ++ solo pueden invocar funciones que se adhieran a una "convención de llamada" que el compilador entiende y espera. (El código de ensamblaje puede usar cualquier convención que le guste, o incluso ninguna, por lo que es posible que el código no se pueda llamar directamente.) Afortunadamente, cada compilador que se respeta a sí mismo proporciona una forma integrada de usar las convenciones comunes de la plataforma. (Los compiladores de Windows C, por ejemplo, le permiten tener / usar funciones que usan las convenciones "cdecl", "stdcall" o "fastcall"). Pero el código de ensamblado debe usar una convención que el compilador conoce, o C y C ++ pueden ' t llamarlo directamente.
cHao
2
Además: la E / S mapeada en memoria es común, pero no toda la historia. Las PC, por ejemplo, comúnmente abordan puertos serie, unidades de disco, etc., utilizando los "puertos de E / S" del x86, un mecanismo completamente diferente. (La memoria intermedia de vídeo es generalmente asignado en memoria, pero de vídeo modos etc se controla típicamente a través de puertos I / O.)
Chao
@cHao: Por supuesto, el enfoque clásico que usa INP y OUTP se está eliminando a favor de DMA; la generación PCI parece hacer más con los registros de funciones especiales mapeados en memoria, ahora que hay una manera de mapear automáticamente los dispositivos a regiones no superpuestas y descubrirlos desde los controladores, y menos con puertos de E / S.
Ben Voigt
los periféricos modernos usarán DMA para la transferencia de datos masivos, pero aún así programará el controlador DMA con memoria direccionable
doron
@doron: Umm, usted programa el controlador DMA a través del espacio de direcciones de E / S (no el espacio de memoria) en una PC, al menos si está sano. A las CPU x86 modernas les gusta reordenar los accesos a la memoria para mejorar el rendimiento. Con MMIO, eso puede ser desastroso ... por lo que deberías tener cuidado de que esas direcciones no se guarden en caché y poner las instrucciones de serialización en todos los lugares correctos. OTOH, el propio x86 asegura que las lecturas y escrituras en el espacio de E / S se realicen en orden de programa. Es por eso que muchas de las cosas importantes todavía se realizan a través del espacio de E / S (que generalmente no es accesible a través de un puntero), y probablemente siempre lo será.
cHao
23

Los lenguajes (como C ++ 11 ) son especificaciones , en papel, generalmente escritas en inglés. Mire el último borrador de C ++ 11 (o compre la costosa especificación final de su proveedor de ISO).

Generalmente usa una computadora con alguna implementación de lenguaje (en principio, podría ejecutar un programa C ++ sin ninguna computadora, por ejemplo, usando un montón de esclavos humanos interpretándolo; eso sería poco ético e ineficiente)

Su implementación general de C ++ funciona por encima de algún sistema operativo y se comunica con él (usando algún código específico de implementación , a menudo en alguna biblioteca del sistema). En general, esa comunicación se realiza a través de llamadas del sistema . Busque, por ejemplo, en syscalls (2) para obtener una lista de las llamadas al sistema disponibles en el kernel de Linux .

Desde el punto de vista de la aplicación, un syscall es una instrucción de máquina elemental como SYSENTERen x86-64 con algunas convenciones ( ABI )

En mi escritorio Linux, las bibliotecas Qt están por encima de las bibliotecas cliente X11 que se comunican con el servidor X11 Xorg a través de los protocolos X Windows .

En Linux, use ldden su ejecutable para ver la lista (larga) de dependencias en las bibliotecas. Úselo pmapen su proceso de ejecución para ver cuáles están "cargados" en tiempo de ejecución. Por cierto, en Linux, su aplicación probablemente esté usando solo software libre, podría estudiar su código fuente (desde Qt, a Xlib, libc, ... el kernel) para comprender más lo que está sucediendo

Basile Starynkevitch
fuente
2
Como referencia, ANSI vende la especificación C ++ 11 por el precio ligeramente menos escandaloso de US $ 60. (Solía ​​ser la mitad de eso, pero la inflación.: P) Está etiquetado como INCITS / ISO / IEC 14882, pero es al menos la misma especificación básica que ofrece ISO. No estoy seguro acerca de las erratas / TRs.
cHao
19

Creo que el concepto que te estás perdiendo son las llamadas al sistema . Cada sistema operativo proporciona una enorme cantidad de recursos y funcionalidades que puede aprovechar para hacer cosas relacionadas con el sistema operativo de bajo nivel. Incluso cuando llama a una función de biblioteca normal, probablemente esté haciendo una llamada al sistema detrás de escena.

Las llamadas al sistema son una forma de bajo nivel de hacer uso de la potencia del sistema operativo, pero pueden ser complejas y engorrosas de usar, por lo que a menudo están "envueltas" en API para que no tenga que lidiar con ellas directamente. Pero debajo, casi cualquier cosa que haga que involucre recursos relacionados con O / S utilizará llamadas al sistema, incluida la impresión, la conexión en red y los sockets, etc.

En el caso de Windows, Microsoft Windows tiene su GUI realmente escrita en el kernel, por lo que hay llamadas del sistema para hacer ventanas, pintar gráficos, etc. En otros sistemas operativos, la GUI puede no ser parte del kernel, en cuyo caso por lo que sé, no habría ninguna llamada al sistema para cosas relacionadas con la GUI, y solo podría trabajar en un nivel aún más bajo con los gráficos de bajo nivel y las llamadas relacionadas con la entrada disponibles.

Dave Cousineau
fuente
3
Lo importante que falta es que esas llamadas al sistema no son mágicas. Son atendidos por el núcleo, que normalmente está escrito en C (++). Además, las llamadas al sistema ni siquiera son necesarias. En un sistema operativo rudimentario sin protección de memoria, las ventanas se pueden dibujar colocando píxeles directamente en el framebuffer de hardware.
el.pescado
15

Buena pregunta. Todo desarrollador nuevo de C o C ++ tiene esto en mente. Asumo una máquina x86 estándar para el resto de esta publicación. Si está utilizando el compilador de Microsoft C ++, abra su bloc de notas y escriba esto (nombre el archivo Test.c)

int main(int argc, char **argv)
{
   return 0
}

Y ahora compile este archivo (usando el símbolo del sistema del desarrollador) cl Test.c /FaTest.asm

Ahora abra Test.asm en su bloc de notas. Lo que ves es el código traducido: C / C ++ se traduce al ensamblador. ¿Entiendes la pista?

_main   PROC
    push    ebp
    mov ebp, esp
    xor eax, eax
    pop ebp
    ret 0
_main   ENDP

Los programas C / C ++ están diseñados para ejecutarse en el metal. Lo que significa que tienen acceso a hardware de nivel inferior, lo que facilita la explotación de las capacidades del hardware. Digamos que voy a escribir una biblioteca C getch () en una máquina x86.

Dependiendo del ensamblador, escribiría algo de esta manera:

_getch proc 
   xor AH, AH
   int 16h
   ;AL contains the keycode (AX is already there - so just return)
ret

Lo ejecuto con un ensamblador y genero un .OBJ: nómbralo getch.obj.

Luego escribo un programa en C (no # incluyo nada)

extern char getch();

void main(int, char **)
{
  getch();
}

Ahora nombre este archivo: GetChTest.c. Compile este archivo pasando getch.obj. (O compile individualmente en .obj y LINK GetChTest.Obj y getch.Obj juntos para producir GetChTest.exe).

Ejecute GetChTest.exe y encontrará que espera la entrada del teclado.

La programación C / C ++ no se trata solo del lenguaje. Para ser un buen programador de C / C ++, debe tener una buena comprensión del tipo de máquina que ejecuta. Necesitará saber cómo se maneja la administración de la memoria, cómo están estructurados los registros, etc. Es posible que no necesite toda esta información para la programación regular, pero lo ayudarían inmensamente. Además del conocimiento básico del hardware, ciertamente ayuda si comprende cómo funciona el compilador (es decir, cómo se traduce), lo que podría permitirle modificar su código según sea necesario. Es un paquete interesante!

Ambos idiomas admiten la palabra clave __asm, lo que significa que también puede mezclar su código de lenguaje ensamblador. Aprender C y C ++ te convertirá en un programador más completo en general.

No es necesario vincularse siempre con Assembler. Lo mencioné porque pensé que eso te ayudaría a entender mejor. En su mayoría, la mayoría de las llamadas a la biblioteca hacen uso de las llamadas al sistema / API proporcionadas por el sistema operativo (el sistema operativo a su vez hace las cosas de interacción de hardware).

Krishna Santosh Sampath
fuente
10

¿Cómo C ++ ... de repente obtiene tales capacidades a través de bibliotecas escritas en C ++?

No hay nada mágico en usar otras bibliotecas. Las bibliotecas son grandes bolsas simples de funciones a las que puede llamar.

Considérate escribiendo una función como esta

void addExclamation(std::string &str)
{
    str.push_back('!');
}

Ahora, si incluye ese archivo, puede escribir addExclamation(myVeryOwnString); . Ahora puede preguntarse, "¿cómo C ++ de repente obtuvo la capacidad de agregar signos de exclamación a una cadena?" La respuesta es fácil: escribiste una función para hacer eso y luego la llamaste.

Entonces, para responder a su pregunta sobre cómo C ++ puede obtener capacidades para dibujar ventanas a través de bibliotecas escritas en C ++, la respuesta es la misma. Alguien más escribió funciones para hacer eso, y luego las compiló y se las dio en forma de biblioteca.

Las otras preguntas responden cómo funciona realmente el dibujo de la ventana, pero parecía confundido sobre cómo funcionan las bibliotecas, por lo que quería abordar la parte más fundamental de su pregunta.

Philip
fuente
8

La clave es la posibilidad del sistema operativo de exponer una API y una descripción detallada de cómo se utilizará esta API.

El sistema operativo ofrece un conjunto de API con convenciones de llamada. La convención de llamada define la forma en que se proporciona un parámetro en la API y cómo se devuelven los resultados y cómo ejecutar la llamada real.

Los sistemas operativos y los compiladores que crean código para ellos juegan muy bien juntos, por lo que generalmente no tiene que pensarlo, solo úselo.

thst
fuente
7

No hay necesidad de una sintaxis especial para crear ventanas. Todo lo que se requiere es que el sistema operativo proporcione una API para crear ventanas. Dicha API consiste en llamadas a funciones simples para las que C ++ proporciona sintaxis.

Además, C y C ++ se denominan lenguajes de programación de sistemas y pueden acceder a punteros arbitrarios (que el hardware podría asignar a algún dispositivo). Además, también es bastante simple llamar a las funciones definidas en el ensamblaje, lo que permite la gama completa de operaciones que proporciona el procesador. Por lo tanto, es posible escribir un sistema operativo en sí mismo usando C o C ++ y una pequeña cantidad de ensamblaje.

También debería mencionarse que Qt es un mal ejemplo, ya que utiliza un llamado meta compilador para extender la sintaxis de C ++. Sin embargo, esto no está relacionado con su capacidad de llamar a las API proporcionadas por el sistema operativo para dibujar o crear ventanas.

Joe
fuente
7

Primero, creo que hay un pequeño malentendido

¿Cómo funciona C ++, que anteriormente no tenía sintaxis capaz de pedirle al sistema operativo una ventana o una forma de comunicarse a través de redes?

No hay sintaxis para realizar operaciones del sistema operativo. Es la cuestión de la semántica .

De repente obtener tales capacidades a través de bibliotecas escritas en C ++

Bueno, el sistema operativo está escrito principalmente en C. Puede usar bibliotecas compartidas (dll) para llamar al código externo. Además, el código del sistema operativo puede registrar rutinas del sistema en syscalls * o interrupciones a las que puede llamar mediante ensamblaje . Las bibliotecas compartidas a menudo solo hacen que el sistema lo llame, por lo que se ahorra el uso del ensamblaje en línea.

Aquí está el buen tutorial sobre eso: http://www.win.tue.nl/~aeb/linux/lk/lk-4.html
Es para Linux, pero los principios son los mismos.

¿Cómo está haciendo el sistema operativo operaciones en tarjetas gráficas, tarjetas de red, etc.? Es un tema muy amplio, pero principalmente necesita acceder a interrupciones, puertos o escribir algunos datos en una región de memoria especial. Como esas operaciones están protegidas, debe llamarlas a través del sistema operativo de todos modos.

Marinero danubiano
fuente
7

En un intento de proporcionar una visión ligeramente diferente a otras respuestas, responderé así.

(Descargo de responsabilidad: estoy simplificando un poco las cosas, la situación que doy es puramente hipotética y está escrita como un medio para demostrar conceptos en lugar de ser 100% fiel a la vida).

Piense en las cosas desde la otra perspectiva, imagine que acaba de escribir un sistema operativo simple con capacidades básicas de enhebrado, ventanas y administración de memoria. Desea implementar una biblioteca C ++ para permitir que los usuarios programen en C ++ y hagan cosas como hacer ventanas, dibujar en ventanas, etc. La pregunta es cómo hacer esto.

En primer lugar, dado que C ++ compila el código de la máquina, debe definir una forma de utilizar el código de la máquina para interactuar con C ++. Aquí es donde entran las funciones, las funciones aceptan argumentos y dan valores de retorno, por lo que proporcionan una forma estándar de transferir datos entre diferentes secciones de código. Lo hacen estableciendo algo conocido como una convención de convocatoria .

Una convención de llamada establece dónde y cómo deben colocarse los argumentos en la memoria para que una función pueda encontrarlos cuando se ejecuta. Cuando se llama a una función, la función de llamada coloca los argumentos en la memoria y luego le pide a la CPU que salte a la otra función, donde hace lo que hace antes de volver a donde fue llamada. Esto significa que el código que se llama puede ser absolutamente cualquier cosa y no cambiará cómo se llama la función. Sin embargo, en este caso, el código detrás de la función sería relevante para el sistema operativo y funcionaría en el estado interno del sistema operativo.

Entonces, muchos meses después y tienes todas tus funciones del sistema operativo ordenadas. Su usuario puede llamar a funciones para crear ventanas y dibujar en ellas, puede hacer hilos y todo tipo de cosas maravillosas. Sin embargo, aquí está el problema, las funciones de su sistema operativo serán diferentes a las funciones de Linux o de Windows. Por lo tanto, decide que necesita darle al usuario una interfaz estándar para que pueda escribir código portátil. Aquí es donde entra QT.

Como es casi seguro que sabe, QT tiene muchas clases y funciones útiles para hacer las cosas que hacen los sistemas operativos, pero de una manera que parece independiente del sistema operativo subyacente. La forma en que esto funciona es que QT proporciona clases y funciones que son uniformes en la forma en que aparecen para el usuario, pero el código detrás de las funciones es diferente para cada sistema operativo. Por ejemplo, QApplication :: closeAllWindows () de QT realmente llamaría a la función de cierre de ventana especializada de cada sistema operativo, dependiendo de la versión utilizada. En Windows, lo más probable es que llame a CloseWindow (hwnd), mientras que en un sistema operativo que usa el sistema X Window, podría llamar a XDestroyWindow (pantalla, ventana).

Como es evidente, un sistema operativo tiene muchas capas, todas las cuales deben interactuar a través de interfaces de muchas variedades. Hay muchos aspectos que ni siquiera he mencionado, pero explicarlos llevaría mucho tiempo. Si está más interesado en el funcionamiento interno de los sistemas operativos, le recomiendo consultar el wiki de desarrollo del sistema operativo .

Sin embargo, tenga en cuenta que la razón por la que muchos sistemas operativos eligen exponer las interfaces a C / C ++ es que compilan el código de la máquina, permiten que las instrucciones de ensamblaje se mezclen con su propio código y brindan un gran grado de libertad al programador.

Una vez más, están pasando muchas cosas aquí. Me gustaría continuar explicando cómo las bibliotecas como .so y .dll no tienen que escribirse en C / C ++ y pueden escribirse en ensamblador u otros lenguajes, pero siento que si agrego más, también podría escribir un artículo completo, y por mucho que me gustaría hacer eso, no tengo un sitio para alojarlo.

Pharap
fuente
6

Cuando intenta dibujar algo en la pantalla, su código llama a otro código que llama a otro código (etc.) hasta que finalmente hay una "llamada al sistema", que es una instrucción especial que la CPU puede ejecutar. Estas instrucciones se pueden escribir en ensamblador o en C ++ si el compilador admite sus "intrínsecos" (que son funciones que el compilador maneja "especialmente" al convertirlas en un código especial que la CPU puede entender). Su trabajo es decirle al sistema operativo que haga algo.

Cuando ocurre una llamada al sistema, se llama a una función que llama a otra función (etc.) hasta que finalmente se le indica al controlador de pantalla que dibuje algo en la pantalla. En ese punto, el controlador de pantalla observa una región particular en la memoria física que en realidad no es memoria, sino más bien un rango de direcciones en el que se puede escribir como si fuera memoria. Sin embargo, escribir en ese rango de direcciones hace que el hardware de gráficos intercepte la escritura de la memoria y dibuje algo en la pantalla.
Escribir en esta región de memoria es algo que podría codificarse en C ++, ya que en el lado del software es solo un acceso de memoria normal. Es solo que el hardware lo maneja de manera diferente.
una explicación realmente básica de cómo puede funcionar.

usuario541686
fuente
44
Afaik, una llamada al sistema no es realmente una instrucción de CPU, y no tiene nada que ver con lo intrínseco. Es más una función del núcleo del sistema operativo, que se comunica con los dispositivos.
MatthiasB
3
@MatthiasB: Bueno, te equivocas, ya que syscall(y su primo sysenter) es de hecho una instrucción de CPU.
user541686
2
Esto fue simplemente una pista para mejorar su respuesta, ya que no estaba claro para mí. No lo veas como un ataque personal ni nada.
MatthiasB
1
@MatthiasB: No lo estoy tomando personalmente. Digo que ya sé que la respuesta no es 100% precisa, pero creo que es una simplificación lo suficientemente buena como para responder al OP, por lo tanto, si realmente conoce una manera de escribir una mejor respuesta, escriba su propia respuesta. responde o toma el tiempo de editar el mío. Realmente no tengo nada que agregar que creo que vale la pena, así que si quieres ver algo mejor en esta página, tendrás que esforzarte tú mismo.
user541686
3
Las llamadas al sistema se realizan mediante interrupciones de software. Instrucciones como sysenterrutas de llamadas optimizadas, ya que el cambio de contexto utilizado por los manejadores de interrupciones no fue tan rápido como todos deseaban, pero fundamentalmente sigue siendo una interrupción generada por software mientras se maneja mediante vectorización a un manejador instalado por el núcleo del sistema operativo. Parte del proceso de cambio de contexto que IS realiza sysenteres cambiar los bits de modo en el procesador para establecer el anillo 0: acceso completo a todas las instrucciones privilegiadas, registros y áreas de memoria y E / S.
Ben Voigt
4

Su programa C ++ está utilizando la biblioteca Qt (también codificada en C ++). La biblioteca Qt utilizará la función Windows CreateWindowEx (que se codificó en C dentro de kernel32.dll). O en Linux puede estar usando Xlib (también codificado en C), pero también podría estar enviando los bytes sin procesar que en el protocolo X significan " Por favor, cree una ventana para mí ".

Relacionado con su pregunta catch-22 está la nota histórica de que "el primer compilador de C ++ fue escrito en C ++", aunque en realidad era un compilador de C con algunas nociones de C ++, lo suficiente como para poder compilar la primera versión, que luego podría compilarse .

De manera similar, el compilador GCC usa extensiones GCC: primero se compila en una versión y luego se usa para recompilarse. (Instrucciones de compilación de GCC)

Ángel
fuente
2

Como veo la pregunta, esta es en realidad una pregunta del compilador.

Míralo de esta manera, escribes un fragmento de código en ensamblador (puedes hacerlo en cualquier idioma) que traduce tu lenguaje recién escrito al que quieres llamar Z ++ en ensamblador, por simplicidad vamos a llamarlo compilador (es un compilador) .

Ahora le da a este compilador algunas funciones básicas, para que pueda escribir int, string, arrays, etc. en realidad le da suficientes habilidades para que pueda escribir el compilador en Z ++. y ahora tienes un compilador para Z ++ escrito en Z ++, bastante bien.

Lo que es aún mejor es que ahora puedes agregar habilidades a ese compilador usando las habilidades que ya tiene, expandiendo así el lenguaje Z ++ con nuevas funciones usando las funciones anteriores

Un ejemplo, si escribe suficiente código para dibujar un píxel en cualquier color, puede expandirlo usando Z ++ para dibujar lo que quiera.

Thomas Andreè Wang
fuente
0

El hardware es lo que permite que esto suceda. Puede pensar en la memoria de gráficos como una gran matriz (que consta de cada píxel en la pantalla). Para dibujar en la pantalla, puede escribir en esta memoria usando C ++ o cualquier lenguaje que permita el acceso directo a esa memoria. Esa memoria resulta accesible o ubicada en la tarjeta gráfica.

En los sistemas modernos, acceder a la memoria gráfica directamente requeriría escribir un controlador debido a varias restricciones, por lo que debe utilizar medios indirectos. Bibliotecas que crean una ventana (realmente solo una imagen como cualquier otra imagen) y luego escriben esa imagen en la memoria gráfica que la GPU muestra en la pantalla. No se debe agregar nada al idioma, excepto la capacidad de escribir en ubicaciones de memoria específicas, para lo que sirven los punteros.

Juan
fuente
El punto que estaba tratando de hacer es que un lenguaje no necesita "expandirse" en el sentido de que una nueva versión del lenguaje necesita ser reescrita, y que no es realmente circular ya que para hacer un programa interesante debe interactuar con el hardware.
juan