Como um idioma se expande? [fechadas]

208

Estou aprendendo C ++ e comecei a aprender sobre alguns dos recursos do Qt para codificar programas GUI. Eu me fiz a seguinte pergunta:

Como o C ++, que anteriormente não tinha sintaxe capaz de solicitar ao sistema operacional uma janela ou uma maneira de se comunicar através de redes (com APIs que eu também não entendo completamente, admito), de repente obtém esses recursos através de bibliotecas escritas em C ++? Tudo parece terrivelmente circular para mim. Quais instruções do C ++ você poderia criar nessas bibliotecas?

Sei que essa pergunta pode parecer trivial para um desenvolvedor de software experiente, mas estou pesquisando há horas sem encontrar nenhuma resposta direta. Chegou ao ponto em que não consigo seguir o tutorial sobre o Qt porque a existência de bibliotecas é incompreensível para mim.

Med Larbi Sentissi
fonte
27
Como o std :: cout desenha alguma coisa no monitor? Ou fica em cima de um compilador que entende seu hardware?
doctorlove 28/07
14
Ótima pergunta. Por fim, é difícil responder até você estudar o hardware.
user541686
17
Qt não é uma expansão da linguagem (isso exigiria um compilador compatível com Qt). É apenas uma biblioteca que é adicionada ao seu arsenal. Eventualmente, no nível mais baixo, todas as bibliotecas se comunicam com o sistema operacional por meio de chamadas do sistema, independentes do idioma, mas muito dependentes do sistema operacional e da arquitetura da CPU.
DevSolar
8
afaik, C ++ tem em linha de montagem, o que pode fazer praticamente qualquer coisa
Display Name
9
@ DevSolar: Na verdade, o Qt expande o idioma com seu próprio mecanismo de slot de sinal, reflexão e muitos outros recursos dinâmicos. E essas coisas exigem um compilador (o compilador de meta-objeto) para compilar até o código C ++.
Siyuan Ren

Respostas:

194

Um computador é como uma cebola, tem muitas muitas camadas, a partir do núcleo interno de hardware puro para a camada mais externa aplicação. Cada camada expõe partes de si mesma para a próxima camada externa, para que a camada externa possa usar parte da funcionalidade das camadas internas.

No caso do Windows, por exemplo, o sistema operacional expõe a API WIN32 para aplicativos em execução no Windows. A biblioteca Qt usa essa API para fornecer aplicativos usando Qt para sua própria API. Você usa Qt, Qt usa WIN32, WIN32 usa níveis mais baixos do sistema operacional Windows e assim por diante, até que haja sinais elétricos no hardware.

Algum cara programador
fonte
56
Nota: Qtaqui fornece uma abstração da camada abaixo dela, porque no Linux Qtchama a API do Linux e não a API do WIN32.
Matthieu M.
5
Provavelmente eu elaboraria um pouco mais sobre o exemplo do Qt, que apenas aparece, como se estendesse sem esforço os recursos do c ++. Quando a realidade é, eles se esforçam muito para criar uma API comum e (de maneira discutível) muitos "núcleos de cebola" diferentes. São eles que fornecem portabilidade em cima de back-end não-portáteis e não-padrão.
Luk32
81
Um computador é como uma cebola: cortá-lo faz você chorar, mas depois fica um pouco saboroso.
Alecov
3
@ChristopherPfohl Sim, tive que usá-lo, já que eu não conseguia descobrir como um computador seria como uma caixa de chocolates. :)
Algum programador,
1
@Celeritas o professor provavelmente disse user32.dll, ou possivelmente gdi32.dll.
user253751
59

Você está certo que, em geral, as bibliotecas não podem tornar possível qualquer coisa que ainda não seja possível.

Mas as bibliotecas não precisam ser escritas em C ++ para serem usadas por um programa em C ++. Mesmo que sejam escritos em C ++, eles podem usar internamente outras bibliotecas não escritas em C ++. Portanto, o fato de o C ++ não fornecer nenhuma maneira de fazê-lo não impede que ele seja adicionado, desde que haja alguma maneira de fazê-lo fora do C ++.

Em um nível bastante baixo, algumas funções chamadas por C ++ (ou C) serão gravadas em assembly, e o assembly contém as instruções necessárias para fazer o que não é possível (ou não é fácil) no C ++, por exemplo, para chamar uma função do sistema. Nesse ponto, essa chamada do sistema pode fazer tudo o que seu computador é capaz, simplesmente porque não há nada para impedi-lo.


fonte
Você quer dizer que as bibliotecas escritas nos outros idiomas já foram compiladas usando outros compiladores? E então teria que haver algum tipo de arquivo de interface vinculando cada chamada de função fornecida ao C ++ pela biblioteca para uma versão pré-compilada da biblioteca? Assim, permitindo que o compilador C ++ saiba o que traduzir essas chamadas?
Med Larbi Sentissi
2
@MedLarbiSentissi 1) Não necessariamente outros compiladores. É possível (e acontece frequentemente) que um único compilador seja capaz de compilar várias linguagens, incluindo assembly, e pode até ser capaz de compilar C ++ com assembly embutido. 2) Dependendo do sistema e compilador específico, a possibilidade de chamar essas funções a partir do C ++ pode ser feita com algum tipo de arquivo de interface, mas esse tipo de arquivo de interface já pode ser um cabeçalho C (ou mesmo C ++) diretamente utilizável pelo C ++.
1
@MedLarbiSentissi: Muitas bibliotecas do Windows são compiladas em arquivos DLL que contêm sua própria interface, bem como o código. Você pode espiar uma dll e ver uma lista das funções que ela permite que você use. Eles geralmente também vêm com um arquivo de cabeçalho C. Quando você cria seu exe, ele contém uma lista das DLLs que precisam ser executadas. Quando o sistema operacional tenta carregar o seu exe, ele automaticamente carregará essas DLLs antes de iniciar a execução.
Mooing Duck
8
Essa resposta parece sugerir que a "mágica" está completamente em outras linguagens sendo chamadas, mas na verdade a maior parte do código que constitui a maioria dos sistemas operacionais modernos é C (com apenas peças muito vinculadas ao hardware ou críticas ao desempenho, escritas em assembly) - e é definitivamente possível usar C ++. O ponto é que não há "mágica", as linguagens são criadas para criar abstrações tão poderosas e, uma vez que você pode interagir com o hardware, as possibilidades são quase ilimitadas.
Matteo Italia
1
@ hvd Acho que todo o conflito nesta discussão é que você (e outros) definem C como os recursos especificados para ele. De fato, os compiladores adicionam muito mais do que o especificado, tornando a pergunta sobre o que C é meio trivial de responder. Para mim, o que há de especial em uma linguagem (portanto, a que ela é) é a meta-maneira de expressar o fluxo do programa e as possibilidades de estruturar. Os elementos que são estruturados não são importantes para ele, já que é apenas mais agradável ASM-código que pode ser adicionado por compiladores como quiserem
LionC
43

C e C ++ têm duas propriedades que permitem toda essa extensibilidade de que o OP está falando.

  1. C e C ++ podem acessar a memória
  2. C e C ++ podem chamar código de assembly para obter instruções que não estão na linguagem C ou C ++.

No kernel ou em uma plataforma básica não protegida, periféricos como a porta serial ou a unidade de disco são mapeados no mapa de memória da mesma maneira que a RAM. A memória é uma série de comutadores e, alternando os comutadores do periférico (como uma porta serial ou driver de disco), o periférico faz coisas úteis.

Em um sistema operacional em modo protegido, quando se deseja acessar o kernel no espaço do usuário (digamos, ao gravar no sistema de arquivos ou desenhar um pixel na tela), é necessário fazer uma chamada do sistema. C não tem instruções para fazer chamadas de sistema, mas C pode chamar código do assembler que pode acionar a chamada correta do sistema. É isso que permite que o código C de uma pessoa fale com o kernel.

Para facilitar a programação de uma plataforma específica, as chamadas do sistema são agrupadas em funções mais complexas que podem desempenhar alguma função útil no próprio programa. Um é livre para ligar diretamente para o sistema (usando o assembler), mas provavelmente é mais fácil usar apenas uma das funções do wrapper que a plataforma fornece.

Há outro nível de API que é muito mais útil do que uma chamada do sistema. Tomemos, por exemplo, malloc. Isso não apenas chamará o sistema para obter grandes blocos de memória, mas também gerenciará essa memória, fazendo todo o registro contábil do que está ocorrendo.

APIs do Win32 agrupam algumas funcionalidades gráficas com um conjunto de widgets de plataforma comum. O Qt leva isso um pouco mais longe, envolvendo a API do Win32 (ou X Windows) de uma maneira multiplataforma.

Fundamentalmente, embora um compilador C transforme código C em código de máquina e, como o computador foi projetado para usar código de máquina, você deve esperar que C consiga realizar o compartilhamento do Lions ou o que um computador pode fazer. Tudo o que as bibliotecas de wrapper fazem é o trabalho pesado para você, para que você não precise.

Doron
fonte
Advertência sobre o item 2: C e C ++ só podem chamar funções viáveis ​​que aderem a uma "convenção de chamada" que o compilador entende e espera. (O código do assembly pode usar qualquer convenção que você goste, ou mesmo nenhuma - por isso o código pode não ser chamado diretamente.) Felizmente, todo compilador que se preze fornece uma maneira integrada de usar as convenções comuns da plataforma. (Os compiladores do Windows C, por exemplo, permitem / têm funções que usam as convenções "cdecl", "stdcall" ou "fastcall".) Mas o código do assembly deve usar uma convenção que o compilador conhece, ou C e C ++ podem ' não ligue diretamente.
cHao 28/07
2
Além disso: a E / S mapeada na memória é comum, mas não a história toda. Os PCs, por exemplo, geralmente endereçam portas seriais, unidades de disco etc. usando as "portas de E / S" do x86, um mecanismo totalmente diferente. (O buffer de vídeo é geralmente de memória mapeada, mas vídeo modos etc são tipicamente controlado por meio de portas de E / S.)
Chao
@cHao: É claro que a abordagem clássica usando INP e OUTP está se destacando em favor do DMA; a geração PCI parece fazer mais com os registros de funções especiais mapeados na memória, agora que existe uma maneira de mapear automaticamente dispositivos para regiões não sobrepostas e descobri-los a partir de drivers e menos com portas de E / S.
Ben Voigt
periféricos modernos vai usar DMA para a transferência de dados em massa, mas você ainda vai programar o controlador DMA com memória endereçável
Doron
@doron: Umm, você programa o controlador DMA através do espaço de endereço de E / S (não do espaço de memória) em um PC, pelo menos se você estiver em bom estado. As CPUs x86 modernas gostam de reordenar acessos à memória para melhorar o desempenho. Com o MMIO, isso pode ser desastroso ... então você precisa ter cuidado para tornar esses endereços inacessíveis e colocar instruções de serialização nos lugares certos. OTOH, o próprio x86 garante que as leituras e gravações no espaço de E / S sejam feitas na ordem do programa. É por isso que grande parte das coisas importantes ainda é feita via espaço de E / S (que geralmente não é acessível por meio de um ponteiro), e provavelmente sempre será.
cHao 29/07
23

Idiomas (como C ++ 11 ) são especificações , em papel, geralmente escritas em inglês. Veja o rascunho mais recente do C ++ 11 (ou compre as especificações finais caras do seu fornecedor ISO).

Você geralmente usa um computador com alguma implementação de linguagem (em princípio, você pode executar um programa C ++ sem nenhum computador, por exemplo, usando vários escravos humanos para interpretá-lo; isso seria antiético e ineficiente)

Sua implementação geral do C ++ funciona acima de algum sistema operacional e se comunica com ele (usando algum código específico da implementação , geralmente em alguma biblioteca do sistema). Geralmente essa comunicação é feita através de chamadas do sistema . Procure, por exemplo, em syscalls (2), uma lista de chamadas do sistema disponíveis no kernel do Linux .

Do ponto de vista do aplicativo, um syscall é uma instrução elementar da máquina, como SYSENTERno x86-64 com algumas convenções ( ABI )

Na área de trabalho do Linux, as bibliotecas Qt estão acima das bibliotecas cliente X11 se comunicando com o servidor X11 Xorg através dos protocolos X Windows .

No Linux, use lddno seu executável para ver a (longa) lista de dependências nas bibliotecas. Use pmapno seu processo de execução para ver quais são "carregados" em tempo de execução. BTW, no Linux, seu aplicativo provavelmente está usando apenas software livre, você pode estudar seu código-fonte (de Qt, Xlib, libc, ... o kernel) para entender mais o que está acontecendo

Basile Starynkevitch
fonte
2
Para referência, a ANSI vende a especificação C ++ 11 pelo preço um pouco menos ultrajante de US $ 60. (Costumava ser metade disso, mas inflação.: P) É rotulado como INCITS / ISO / IEC 14882, mas é pelo menos a mesma especificação básica que a ISO oferece. Não tenho certeza sobre erratas / TRs.
cHao 14/08
19

Eu acho que o conceito que você está perdendo são chamadas de sistema . Cada sistema operacional fornece uma enorme quantidade de recursos e funcionalidades nas quais você pode aproveitar para executar tarefas relacionadas ao sistema operacional de baixo nível. Mesmo quando você chama uma função de biblioteca comum, provavelmente está fazendo uma chamada do sistema nos bastidores.

As chamadas do sistema são uma maneira de baixo nível de usar o poder do sistema operacional, mas podem ser complexas e complicadas de usar, por isso geralmente são "encapsuladas" nas APIs para que você não precise lidar com elas diretamente. Porém, por baixo, praticamente qualquer coisa que você faça que envolva recursos relacionados ao sistema operacional usará chamadas do sistema, incluindo impressão, rede e soquetes, etc.

No caso do Windows, o Microsoft Windows tem sua GUI gravada no kernel, portanto, há chamadas do sistema para criação de janelas, gráficos de pintura etc. Em outros sistemas operacionais, a GUI pode não fazer parte do kernel, nesse caso até onde eu sei, não haveria chamadas de sistema para coisas relacionadas à GUI e você só poderia trabalhar em um nível ainda mais baixo com quaisquer gráficos de baixo nível e chamadas relacionadas a entrada disponíveis.

Dave Cousineau
fonte
3
O que falta é que essas chamadas do sistema não sejam de forma alguma mágicas. Eles são atendidos pelo kernel, normalmente escrito em C (++). Além disso, os syscalls nem são necessários. Em sistemas operacionais rudimentares sem proteção de memória, as janelas podem ser desenhadas colocando pixels diretamente no buffer de estrutura do hardware.
el.pescado
15

Boa pergunta. Todo novo desenvolvedor de C ou C ++ tem isso em mente. Estou assumindo uma máquina x86 padrão para o restante deste post. Se você estiver usando o compilador Microsoft C ++, abra o seu bloco de notas e digite este (nomeie o arquivo Test.c)

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

E agora compile esse arquivo (usando o prompt de comando do desenvolvedor) cl Test.c /FaTest.asm

Agora abra Test.asm no seu bloco de notas. O que você vê é o código traduzido - C / C ++ é traduzido para assembler. Você entendeu a dica?

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

Os programas C / C ++ são projetados para rodar no metal. O que significa que eles têm acesso a hardware de nível inferior, o que facilita a exploração dos recursos do hardware. Digamos, eu vou escrever uma biblioteca C getch () em uma máquina x86.

Dependendo do assembler, eu digitaria algo assim:

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

Eu corro com um assembler e giro um .OBJ - Nomeie getch.obj.

Em seguida, escrevo um programa em C (não incluo nada)

extern char getch();

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

Agora, nomeie esse arquivo - GetChTest.c. Compile esse arquivo passando getch.obj. (Ou compile individualmente para .obj e LINK GetChTest.Obj e getch.Obj juntos para produzir GetChTest.exe).

Execute GetChTest.exe e você descobrirá que aguarda a entrada do teclado.

A programação C / C ++ não é apenas sobre linguagem. Para ser um bom programador de C / C ++, você precisa entender bem o tipo de máquina que ele executa. Você precisará saber como o gerenciamento de memória é tratado, como os registros são estruturados, etc. Você pode não precisar de todas essas informações para programação regular - mas elas o ajudarão imensamente. Além do conhecimento básico de hardware, certamente ajuda se você entender como o compilador funciona (por exemplo, como ele se traduz) - o que pode permitir que você ajuste seu código conforme necessário. É um pacote interessante!

Ambos os idiomas suportam a palavra-chave __asm, o que significa que você também pode misturar o código da linguagem assembly. Aprender C e C ++ fará de você um programador arredondado melhor em geral.

Não é necessário sempre vincular ao Assembler. Eu mencionei isso porque pensei que isso ajudaria você a entender melhor. Principalmente, a maioria dessas chamadas de biblioteca utiliza chamadas / APIs do sistema fornecidas pelo sistema operacional (o sistema operacional, por sua vez, faz as coisas de interação do hardware).

Krishna Santosh Sampath
fonte
10

Como o C ++ ... de repente obtém esses recursos por meio de bibliotecas escritas em C ++?

Não há nada mágico em usar outras bibliotecas. Bibliotecas são simples sacos grandes de funções que você pode chamar.

Considere-se escrevendo uma função como esta

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

Agora, se você incluir esse arquivo, poderá escrever addExclamation(myVeryOwnString);. Agora você pode perguntar: "como o C ++ conseguiu repentinamente a capacidade de adicionar pontos de exclamação a uma string?" A resposta é fácil: você escreveu uma função para fazer isso e depois a chamou.

Portanto, para responder sua pergunta sobre como o C ++ pode obter recursos para desenhar janelas através de bibliotecas escritas em C ++, a resposta é a mesma. Outra pessoa escreveu funções para fazer isso e, em seguida, compilou-as e deu-as a você na forma de uma biblioteca.

As outras perguntas respondem como o desenho da janela realmente funciona, mas você parecia confuso sobre como as bibliotecas funcionam, então eu queria abordar a parte mais fundamental da sua pergunta.

Philip
fonte
8

A chave é a possibilidade do sistema operacional expor uma API e uma descrição detalhada de como essa API deve ser usada.

O sistema operacional oferece um conjunto de APIs com convenções de chamada. A convenção de chamada está definindo a maneira como um parâmetro é fornecido na API e como os resultados são retornados e como executar a chamada real.

Os sistemas operacionais e os compiladores que criam o código para eles funcionam muito bem juntos, então você geralmente não precisa pensar nisso, apenas use-o.

thst
fonte
7

Não há necessidade de uma sintaxe especial para criar janelas. Tudo o que é necessário é que o sistema operacional forneça uma API para criar janelas. Essa API consiste em chamadas de função simples para as quais o C ++ fornece sintaxe.

Além disso, C e C ++ são as chamadas linguagens de programação de sistemas e são capazes de acessar ponteiros arbitrários (que podem ser mapeados para algum dispositivo pelo hardware). Além disso, também é bastante simples chamar funções definidas na montagem, o que permite toda a gama de operações que o processador fornece. Portanto, é possível escrever um sistema operacional usando C ou C ++ e uma pequena quantidade de montagem.

Também deve ser mencionado que Qt é um mau exemplo, pois usa o chamado meta compilador para estender a sintaxe do C ++. No entanto, isso não está relacionado à capacidade de chamar as APIs fornecidas pelo sistema operacional para desenhar ou criar janelas.

Joe
fonte
7

Primeiro, há um pouco de mal entendido, eu acho

Como o C ++, que anteriormente não tinha sintaxe capaz de solicitar ao sistema operacional uma janela ou uma maneira de se comunicar através de redes

Não há sintaxe para executar operações do SO. É a questão da semântica .

de repente, obter esses recursos por meio de bibliotecas escritas em C ++

Bem, o sistema operacional é gravado principalmente em C. Você pode usar bibliotecas compartilhadas (portanto, dll) para chamar o código externo. Além disso, o código do sistema operacional pode registrar rotinas do sistema em syscalls * ou interrupções que você pode chamar usando assembly . As bibliotecas compartilhadas costumam fazer esse sistema chamar você, para que você seja poupado usando o assembly embutido.

Aqui está o bom tutorial sobre isso: http://www.win.tue.nl/~aeb/linux/lk/lk-4.html
É para Linux, mas os princípios são os mesmos.

Como o sistema operacional está realizando operações em placas gráficas, placas de rede etc? É um tema muito amplo, mas principalmente você precisa acessar interrupções, portas ou gravar alguns dados em uma região de memória especial. Como essas operações estão protegidas, você precisa chamá-las pelo sistema operacional de qualquer maneira.

Marinheiro Danubiano
fonte
7

Na tentativa de fornecer uma visão ligeiramente diferente para outras respostas, responderei dessa maneira.

(Isenção de responsabilidade: estou simplificando um pouco as coisas, a situação apresentada é puramente hipotética e foi escrita como um meio de demonstrar conceitos, em vez de ser 100% fiel à vida).

Pense nas coisas de outra perspectiva, imagine que você acabou de escrever um sistema operacional simples com recursos básicos de segmentação, janelas e gerenciamento de memória. Você deseja implementar uma biblioteca C ++ para permitir que os usuários programem em C ++ e façam coisas como criar janelas, atrair janelas etc. A questão é: como fazer isso.

Primeiro, como o C ++ é compilado no código da máquina, você precisa definir uma maneira de usar o código da máquina para fazer interface com o C ++. É aqui que as funções entram, as funções aceitam argumentos e fornecem valores de retorno, portanto, elas fornecem uma maneira padrão de transferir dados entre diferentes seções do código. Eles fazem isso estabelecendo algo conhecido como convenção de chamada .

Uma convenção de chamada indica onde e como os argumentos devem ser colocados na memória para que uma função possa encontrá-los quando for executada. Quando uma função é chamada, a função de chamada coloca os argumentos na memória e solicita à CPU que pule para a outra função, onde faz o que faz antes de voltar para onde foi chamada. Isso significa que o código que está sendo chamado pode ser absolutamente qualquer coisa e não muda como a função é chamada. Nesse caso, no entanto, o código por trás da função seria relevante para o sistema operacional e operaria no estado interno do sistema operacional.

Portanto, muitos meses depois, você terá todas as suas funções de sistema operacional resolvidas. Seu usuário pode chamar funções para criar janelas e desenhar nelas, pode criar threads e todo tipo de coisas maravilhosas. Mas aqui está o problema: as funções do seu sistema operacional serão diferentes das funções do Linux ou do Windows. Portanto, você decide fornecer ao usuário uma interface padrão para que ele possa escrever um código portátil. Aqui é onde entra o QT.

Como você quase certamente sabe, o QT possui muitas classes e funções úteis para realizar as tarefas que os sistemas operacionais fazem, mas de uma maneira que parece independente do sistema operacional subjacente. A maneira como isso funciona é que o QT fornece classes e funções uniformes na aparência para o usuário, mas o código por trás das funções é diferente para cada sistema operacional. Por exemplo, QApplication :: closeAllWindows () do QT estaria chamando a função de fechamento de janela especializada de cada sistema operacional, dependendo da versão usada. No Windows, provavelmente chamaria CloseWindow (hwnd), enquanto em um sistema operacional usando o X Window System, potencialmente chamaria XDestroyWindow (exibição, janela).

Como é evidente, um sistema operacional possui muitas camadas, todas as quais precisam interagir através de interfaces de várias variedades. Há muitos aspectos em que eu nem mencionei, mas explicar todos eles levaria muito tempo. Se você ainda estiver interessado no funcionamento interno dos sistemas operacionais, recomendo consultar o wiki do desenvolvedor do OS .

Lembre-se, porém, que a razão pela qual muitos sistemas operacionais optam por expor interfaces ao C / C ++ é que eles compilam com código de máquina, permitem que as instruções de montagem sejam misturadas com seu próprio código e oferecem um grande grau de liberdade ao programador.

Novamente, há muita coisa acontecendo aqui. Gostaria de continuar explicando como as bibliotecas como arquivos .so e .dll não precisam ser escritas em C / C ++ e podem ser escritas em assembly ou em outras linguagens, mas acho que, se eu adicionar mais, também devo escreva um artigo inteiro e, por mais que eu adorasse, não tenho um site para hospedá-lo.

Pharap
fonte
6

Quando você tenta desenhar algo na tela, seu código chama outro código que chama outro código (etc.) até que finalmente haja uma "chamada do sistema", que é uma instrução especial que a CPU pode executar. Essas instruções podem ser escritas em assembly ou em C ++ se o compilador oferecer suporte a seus "intrínsecos" (que são funções que o compilador manipula "especialmente" convertendo-os em código especial que a CPU possa entender). O trabalho deles é dizer ao sistema operacional para fazer alguma coisa.

Quando ocorre uma chamada do sistema, é chamada uma função que chama outra função (etc.) até que, finalmente, o driver da tela seja instruído a desenhar algo na tela. Nesse ponto, o driver de vídeo examina uma região específica da memória física que na verdade não é memória, mas um intervalo de endereços que pode ser gravado como se fosse memória. Em vez disso, porém, a gravação nesse intervalo de endereços faz com que o hardware gráfico intercepte a gravação na memória e desenhe algo na tela.
Gravar nesta região da memória é algo que pode ser codificado em C ++, pois no lado do software é apenas um acesso regular à memória. Só que o hardware lida com isso de maneira diferente.
Portanto, essa é uma explicação realmente básica de como isso pode funcionar.

user541686
fonte
4
Afaik uma chamada de sistema não é realmente uma instrução de CPU, e não tem nada a ver com intrínsecas. É mais uma função do kernel do sistema operacional, que se comunica com os dispositivos.
perfil
3
@ MatthiasB: Bem, você está errado, já que syscall(e seu primo sysenter) é realmente uma instrução de CPU.
user541686
2
Esta foi apenas uma dica para melhorar sua resposta, pois não estava claro para mim. Não o veja como ataque pessoal ou algo assim.
MatthiasB
1
@ MatthiasB: Eu não estou levando para o lado pessoal. Estou dizendo que já sei que a resposta não é 100% precisa, mas acho que é uma simplificação suficiente o suficiente para responder ao OP - por isso, se você realmente sabe como escrever uma resposta melhor, escreva sua própria responda ou reserve um tempo para editar o meu. Eu realmente não tenho nada a acrescentar que eu acho que vale a pena, então se você quiser ver algo melhor nesta página, terá que se esforçar.
user541686
3
As chamadas do sistema são feitas usando interrupções de software. Instruções como sysentersão caminhos de chamada otimizados, já que a alternância de contexto usada pelos manipuladores de interrupção não foi tão rápida quanto todos desejavam, mas fundamentalmente ainda é uma interrupção gerada por software enquanto é manipulada por vetorização para um manipulador instalado pelo kernel do sistema operacional. Parte do processo de alternância de contexto realizado pelo IS sysenteré alterar os bits de modo no processador para definir o anel 0 - acesso total a todas as instruções privilegiadas, registros e áreas de memória e E / S.
Ben Voigt
4

Seu programa C ++ está usando a biblioteca Qt (também codificada em C ++). A biblioteca Qt estará usando a função Windows CreateWindowEx (que foi codificada em C dentro do kernel32.dll). Ou no Linux, ele pode estar usando o Xlib (também codificado em C), mas também pode estar enviando os bytes brutos que no protocolo X significam " Por favor, crie uma janela para mim ".

Relacionada à sua pergunta catch-22, está a observação histórica de que “o primeiro compilador C ++ foi escrito em C ++”, embora na verdade fosse um compilador C com algumas noções de C ++, o suficiente para compilar a primeira versão, que poderia então se compilar. .

Da mesma forma, o compilador GCC usa extensões GCC: ele é compilado primeiro em uma versão e depois usado para se recompilar. (Instruções de criação do GCC)

Anjo
fonte
2

Como eu vejo a pergunta, essa é realmente uma pergunta do compilador.

Veja desta maneira: você escreve um pedaço de código no Assembly (você pode fazê-lo em qualquer idioma) que traduz seu idioma recém-escrito que deseja chamar Z ++ em Assembly, para simplificar vamos chamá-lo de compilador (é um compilador) .

Agora você fornece a este compilador algumas funções básicas, para que você possa escrever int, string, matrizes etc. e agora você tem um compilador para o Z ++ escrito em Z ++, bem legal.

O que é ainda mais interessante é que agora você pode adicionar habilidades a esse compilador usando as habilidades já existentes, expandindo a linguagem Z ++ com novos recursos usando os recursos anteriores

Por exemplo, se você escrever código suficiente para desenhar um pixel em qualquer cor, poderá expandi-lo usando o Z ++ para desenhar o que quiser.

Thomas Andreè Wang
fonte
0

O hardware é o que permite que isso aconteça. Você pode pensar na memória gráfica como uma grande variedade (consistindo de todos os pixels na tela). Para desenhar na tela, você pode gravar nesta memória usando C ++ ou qualquer idioma que permita acesso direto a essa memória. Por acaso, essa memória está acessível ou localizada na placa gráfica.

Nos sistemas modernos, o acesso direto à memória gráfica exigiria a gravação de um driver devido a várias restrições, para que você use meios indiretos. Bibliotecas que criam uma janela (realmente apenas uma imagem como qualquer outra imagem) e depois gravam essa imagem na memória gráfica que a GPU exibe na tela. Nada precisa ser adicionado ao idioma, exceto a capacidade de gravar em locais específicos da memória, e é para isso que servem os ponteiros.

John
fonte
O ponto que eu estava tentando destacar é que uma linguagem não precisa se "expandir" no sentido de que uma nova versão da linguagem precisa ser reescrita e que não é realmente circular desde que faça algo interessante em um programa deve interagir com o hardware.
john