Come si espande una lingua? [chiuso]


208

Sto imparando il C ++ e ho appena iniziato a conoscere alcune delle capacità di Qt per codificare i programmi GUI. Mi sono posto la seguente domanda:

In che modo il C ++, che in precedenza non aveva una sintassi in grado di chiedere al sistema operativo una finestra o un modo per comunicare attraverso le reti (con API che non capisco del tutto, ammetto) improvvisamente può ottenere tali capacità attraverso le librerie scritte in C ++ stesso?Mi sembra tutto terribilmente circolare. Quali istruzioni C ++ potresti trovare in quelle librerie?

Mi rendo conto che questa domanda potrebbe sembrare banale per uno sviluppatore di software esperto, ma ho cercato per ore senza trovare una risposta diretta. È arrivato al punto in cui non posso seguire il tutorial su Qt perché l'esistenza delle librerie è incomprensibile per me.


27
Come fa std :: cout a disegnare qualcosa sul monitor? O si trova in cima a un compilatore che capisce il tuo hardware?
doctorlove,

14
Ottima domanda Alla fine è difficile rispondere fino a quando non studi l'hardware.
user541686,

17
Qt non è un'espansione del linguaggio (che richiederebbe un compilatore compatibile con Qt). È semplicemente una biblioteca che viene aggiunta al tuo arsenale. Alla fine, al livello più basso tutte le librerie comunicano con il sistema operativo tramite chiamate di sistema, che sono indipendenti dalla lingua, ma dipendono molto dal sistema operativo e dall'architettura della CPU.
DevSolar,

8
afaik, C ++ ha un assembly inline, che può fare praticamente qualsiasi cosa
Visualizza nome

9
@DevSolar: attualmente Qt espande la lingua con il proprio meccanismo di slot del segnale, riflessione e molte altre caratteristiche dinamiche. E queste cose richiedono un compilatore (il compilatore meta oggetto) per compilare fino al codice C ++.
Siyuan Ren,

Risposte:


194

Un computer è come una cipolla, ha molti molti strati, dal nucleo interno di hardware puro allo strato di applicazione più esterno. Ogni strato espone parti di se stesso al successivo strato esterno, in modo che lo strato esterno possa utilizzare alcune delle funzionalità degli strati interni.

Nel caso, ad esempio, di Windows, il sistema operativo espone la cosiddetta API WIN32 per le applicazioni in esecuzione su Windows. La libreria Qt utilizza tale API per fornire applicazioni che utilizzano Qt alla propria API. Si utilizza Qt, Qt utilizza WIN32, WIN32 utilizza livelli inferiori del sistema operativo Windows e così via fino a quando non sono segnali elettrici nell'hardware.


56
Nota: Qtqui fornisce un'astrazione del livello sottostante, perché su Linux Qtinvoca l'API Linux e non l'API WIN32.
Matthieu M.,

5
Probabilmente elaboarte un po 'di più sull'esempio di Qt, che appare, come se estendesse senza sforzo le funzionalità di c ++. Quando la realtà è, hanno fatto un grande sforzo per creare un'API comune, per (debevolmente) molti "nuclei di cipolla" diversi. Sono quelli che offrono portabilità oltre a backend non standard non portatili.
luk32,

81
Un computer è come una cipolla: tagliandolo ti fa piangere, ma dopo è un po 'gustoso.
alecov,

3
@ChristopherPfohl Sì, ho dovuto usarlo perché non riuscivo a capire come sarebbe un computer come una scatola di cioccolatini. :)
Un tizio programmatore, il

1
@Celeritas probabilmente l'insegnante ha detto user32.dll, o forse gdi32.dll.
user253751

59

Hai ragione sul fatto che in generale le biblioteche non possono rendere possibile nulla che non sia già possibile.

Ma le librerie non devono essere scritte in C ++ per essere utilizzabili da un programma C ++. Anche se sono scritti in C ++, possono utilizzare internamente altre librerie non scritte in C ++. Quindi il fatto che il C ++ non abbia fornito alcun modo per farlo non impedisce che venga aggiunto, purché ci sia un modo per farlo al di fuori del C ++.

A un livello abbastanza basso, alcune funzioni chiamate da C ++ (o da C) verranno scritte in assembly e l'assembly contiene le istruzioni necessarie per fare tutto ciò che non è possibile (o non è facile) in C ++, ad esempio chiamare una funzione di sistema. A quel punto, quella chiamata di sistema può fare tutto ciò di cui il tuo computer è capace, semplicemente perché non c'è nulla che lo fermi.


Vuoi dire che quelle librerie scritte in altre lingue sono già compilate usando altri compilatori? E poi ci dovrebbe essere una sorta di file di interfaccia che collega ogni chiamata di funzione fornita a C ++ dalla libreria a una versione precompilata della libreria? Permettendo così al compilatore C ++ di sapere in cosa tradurre quelle chiamate?
Med Larbi Sentissi,

2
@MedLarbiSentissi 1) Non necessariamente altri compilatori. È possibile (e capita spesso) che un singolo compilatore sia in grado di compilare più lingue, incluso assembly, e potrebbe anche essere in grado di compilare C ++ con assembly inline. 2) A seconda del sistema specifico e del compilatore, rendere tali funzioni richiamabili da C ++ può effettivamente essere fatto con una sorta di file di interfaccia, ma quel tipo di file di interfaccia potrebbe già essere un'intestazione C (o persino C ++) direttamente utilizzabile da C ++.

1
@MedLarbiSentissi: molte librerie di Windows sono compilate in file dll che contengono la propria interfaccia e il codice. Puoi sbirciare in una dll e vedere un elenco delle funzioni che ti consente di utilizzare. Spesso vengono anche con un file di intestazione C. Quando crei il tuo exe, contiene un elenco di DLL che deve eseguire. Quando il sistema operativo tenta di caricare il tuo exe, caricherà automaticamente anche quelle dll prima di iniziare l'esecuzione.
Mooing Duck,

8
Questa risposta sembra suggerire che la "magia" risieda completamente in altre lingue chiamate, ma in realtà la maggior parte del codice che costituisce la maggior parte dei sistemi operativi moderni è C (con solo parti molto legate all'hardware o critiche per le prestazioni scritte in assembly) - e è sicuramente possibile usare invece C ++. Il punto è che non c'è "magia", le lingue sono create per costruire astrazioni così potenti e una volta che puoi interagire con l'hardware le possibilità sono quasi illimitate.
Matteo Italia,

1
@hvd Penso che l'intero conflitto in questa discussione sia che tu (e altri) definiate C come le caratteristiche che sono state specificate per esso. In effetti, i compilatori aggiungono molto di più di quanto specificato, rendendo la domanda su cosa sia un po 'banale rispondere. Per me la cosa speciale di un linguaggio (quindi la cosa che è) è il meta-modo per esprimere il flusso del programma e le possibilità di strutturarlo. Gli elementi strutturati non sono importanti per questo, in quanto è solo un codice ASM più bello che può essere aggiunto dai compilatori come vogliono
LionC

43

C e C ++ hanno 2 proprietà che consentono tutta questa estensibilità di cui parla l'OP.

  1. C e C ++ possono accedere alla memoria
  2. C e C ++ possono chiamare il codice assembly per istruzioni non nel linguaggio C o C ++.

Nel kernel o in una piattaforma di modalità non protetta di base, periferiche come la porta seriale o l'unità disco sono mappate nella mappa di memoria allo stesso modo della RAM. La memoria è una serie di switch e capovolgendo gli switch della periferica (come una porta seriale o un driver del disco), la tua periferica fa cose utili.

In un sistema operativo in modalità protetta, quando si desidera accedere al kernel dallo spazio utente (ad esempio quando si scrive nel file system o si disegna un pixel sullo schermo) è necessario effettuare una chiamata di sistema. C non ha un'istruzione per effettuare chiamate di sistema ma C può chiamare il codice assembler che può innescare la corretta chiamata di sistema, questo è ciò che consente al proprio codice C di parlare con il kernel.

Per facilitare la programmazione di una particolare piattaforma, le chiamate di sistema sono racchiuse in funzioni più complesse che possono svolgere alcune funzioni utili all'interno del proprio programma. Uno è libero di chiamare direttamente le chiamate di sistema (usando l'assemblatore) ma è probabilmente più semplice utilizzare una delle funzioni wrapper fornite dalla piattaforma.

Esiste un altro livello di API molto più utile di una chiamata di sistema. Prendi ad esempio malloc. Non solo questo chiamerà il sistema per ottenere grandi blocchi di memoria, ma gestirà questa memoria facendo tutto il libro mantenendo ciò che accade.

Le API Win32 racchiudono alcune funzionalità grafiche con un set di widget di piattaforma comune. Qt lo porta un po 'oltre avvolgendo l'API Win32 (o X Windows) in modo multipiattaforma.

Fondamentalmente anche se un compilatore C trasforma il codice C in codice macchina e poiché il computer è progettato per utilizzare il codice macchina, dovresti aspettarti che C sia in grado di realizzare la condivisione dei leoni o cosa può fare un computer. Tutto ciò che fanno le librerie wrapper è fare il lavoro pesante per te in modo da non doverlo fare.


Avvertenza su # 2: C e C ++ possono solo chiamare in modo fattibile funzioni che aderiscono a una "convenzione di chiamata" che il compilatore comprende e si aspetta. (Il codice assembly può utilizzare qualsiasi convenzione gli piaccia, o addirittura nessuna, quindi il codice potrebbe non essere richiamabile direttamente.) Fortunatamente, ogni compilatore che si rispetti fornisce un modo integrato per utilizzare le convenzioni comuni della piattaforma. (I compilatori di Windows C, ad esempio, consentono di avere / utilizzare funzioni che utilizzano le convenzioni "cdecl", "stdcall" o "fastcall".) Ma il codice assembly deve utilizzare una convenzione che il compilatore conosce, o C e C ++ possono " non chiamarlo direttamente.
cHao,

2
Inoltre: l'I / O mappato in memoria è comune, ma non l'intera storia. I PC, ad esempio, comunemente indirizzano porte seriali, unità disco, ecc. Utilizzando le "porte I / O" dell'86 x, un meccanismo completamente diverso. (Il buffer video è in genere mappato in memoria, ma le modalità video ecc. Sono in genere controllate tramite porte I / O.)
cHao,

@cHao: Naturalmente l'approccio classico che utilizza INP e OUTP si sta delineando a favore di DMA; la generazione PCI sembra fare di più con i registri delle funzioni speciali mappati in memoria, ora che c'è un modo per mappare automaticamente i dispositivi su regioni non sovrapposte e scoprirli dai driver, e meno con le porte I / O.
Ben Voigt,

le moderne periferiche utilizzeranno DMA per il trasferimento di dati in
blocco

@doron: Umm, programmi il controller DMA tramite lo spazio degli indirizzi I / O (non lo spazio di memoria) su un PC, almeno se sei sano di mente. Le moderne CPU x86 amano riordinare gli accessi alla memoria per migliorare le prestazioni. Con MMIO, questo può essere disastroso ... quindi dovresti stare attento a rendere quegli indirizzi unacheabke e mettere le istruzioni di serializzazione in tutti i posti giusti. OTOH, lo stesso x86 assicura che le letture e le scritture nello spazio I / O vengano eseguite nell'ordine del programma. Questo è il motivo per cui gran parte delle cose importanti viene ancora eseguita tramite spazio I / O (che generalmente non è accessibile tramite un puntatore), e probabilmente lo sarà sempre.
cHao,

23

Le lingue (come C ++ 11 ) sono specifiche , su carta, generalmente scritte in inglese. Guarda all'interno dell'ultima bozza C ++ 11 (o acquista le costose specifiche finali dal tuo fornitore ISO).

In genere si utilizza un computer con una certa implementazione della lingua (in linea di principio è possibile eseguire un programma C ++ senza alcun computer, ad esempio utilizzando un gruppo di schiavi umani che lo interpretano; sarebbe immorale e inefficiente)

L'implementazione C ++ in generale funziona al di sopra di alcuni sistemi operativi e comunica con esso (utilizzando un codice specifico per l'implementazione , spesso in alcune librerie di sistema). Generalmente tale comunicazione avviene tramite chiamate di sistema . Cerca ad esempio in syscalls (2) un elenco di chiamate di sistema disponibili sul kernel Linux .

Dal punto di vista dell'applicazione, una syscall è un'istruzione macchina elementare come SYSENTERsu x86-64 con alcune convenzioni ( ABI )

Sul mio desktop Linux, le librerie Qt sono sopra le librerie client X11 che comunicano con i protocolli Xorg attraverso X Windows del server X11 .

Su Linux, usa lddsul tuo eseguibile per vedere l'elenco (lungo) delle dipendenze dalle librerie. Utilizzare pmapsul processo in esecuzione per vedere quali sono "caricati" in fase di esecuzione. A proposito, su Linux, la tua applicazione sta probabilmente usando solo software gratuito, potresti studiare il suo codice sorgente (da Qt, a Xlib, libc, ... il kernel) per capire di più cosa sta succedendo


2
Per riferimento, ANSI vende le specifiche C ++ 11 al prezzo leggermente meno scandaloso di US $ 60. (Prima era metà, ma inflazione.: P) È etichettato come INCITS / ISO / IEC 14882, ma è almeno la stessa specifica di base offerta da ISO. Non sono sicuro di errata / TRs.
cHao,

19

Penso che il concetto che ti manca siano le chiamate di sistema . Ogni sistema operativo fornisce un'enorme quantità di risorse e funzionalità a cui puoi attingere per fare cose relative a sistemi operativi di basso livello. Anche quando chiamate una normale funzione di libreria, probabilmente sta effettuando una chiamata di sistema dietro le quinte.

Le chiamate di sistema sono un modo di basso livello di sfruttare la potenza del sistema operativo, ma possono essere complesse e ingombranti da usare, quindi spesso sono "racchiuse" nelle API in modo da non doverle gestire direttamente. Ma sotto, quasi tutto ciò che fai che coinvolge risorse relative a O / S utilizzerà le chiamate di sistema, inclusi stampa, rete e prese, ecc.

Nel caso di Windows, Microsoft Windows ha la sua GUI effettivamente scritta nel kernel, quindi ci sono chiamate di sistema per creare finestre, disegnare grafica, ecc. In altri sistemi operativi, la GUI potrebbe non far parte del kernel, nel qual caso per quanto ne so non ci sarebbero chiamate di sistema per cose relative alla GUI e si potrebbe lavorare solo a un livello ancora più basso con qualsiasi grafica di basso livello e chiamate relative all'input disponibili.


3
La cosa importante che manca è che quelle chiamate di sistema non sono affatto magiche. Sono serviti dal kernel che è tipicamente scritto in C (++). Inoltre, i syscalls non sono nemmeno necessari. Nel sistema operativo rudimentale senza protezione della memoria, è possibile disegnare Windows inserendo i pixel direttamente nel framebuffer hardware.
el.pescado,

15

Buona domanda. Ogni nuovo sviluppatore C o C ++ ha questo in mente. Sto assumendo una macchina x86 standard per il resto di questo post. Se si utilizza il compilatore Microsoft C ++, aprire il blocco note e digitare questo (denominare il file Test.c)

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

E ora compila questo file (usando il prompt dei comandi dello sviluppatore) cl Test.c /FaTest.asm

Ora apri Test.asm nel tuo blocco note. Quello che vedi è il codice tradotto - C / C ++ viene tradotto in assemblatore. Hai ricevuto il suggerimento?

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

I programmi C / C ++ sono progettati per essere eseguiti sul metallo. Ciò significa che hanno accesso a hardware di livello inferiore che semplifica lo sfruttamento delle capacità dell'hardware. Supponiamo che scriverò una libreria C getch () su una macchina x86.

A seconda dell'assemblatore, scriverei qualcosa in questo modo:

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

L'ho investito con un assemblatore e ho generato un .OBJ - Name it getch.obj.

Quindi scrivo un programma C (non #includo nulla)

extern char getch();

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

Ora dai un nome a questo file: GetChTest.c. Compilare questo file passando getch.obj. (O compilare singolarmente in .obj e LINK GetChTest.Obj e getch.Obj insieme per produrre GetChTest.exe).

Esegui GetChTest.exe e scoprirai che attende l'input da tastiera.

La programmazione C / C ++ non riguarda solo il linguaggio. Per essere un buon programmatore C / C ++ devi avere una buona conoscenza del tipo di macchina che gira. Dovrai sapere come viene gestita la gestione della memoria, come sono strutturati i registri, ecc. Potresti non aver bisogno di tutte queste informazioni per una programmazione regolare, ma ti aiuterebbero immensamente. A parte le conoscenze hardware di base, aiuta sicuramente a capire come funziona il compilatore (cioè, come si traduce) - che potrebbe consentire di modificare il codice secondo necessità. È un pacchetto interessante!

Entrambe le lingue supportano la parola chiave __asm, il che significa che è possibile combinare anche il codice della lingua dell'assembly. Imparare C e C ++ ti renderà un programmatore meglio arrotondato in generale.

Non è necessario collegarsi sempre con Assembler. L'avevo menzionato perché pensavo che ti avrebbe aiutato a capire meglio. Per lo più, la maggior parte di tali chiamate in libreria fanno uso delle chiamate di sistema / API fornite dal sistema operativo (il sistema operativo a sua volta fa le cose di interazione hardware).


10

In che modo C ++ ... ottiene improvvisamente tali capacità attraverso le librerie scritte in C ++?

Non c'è niente di magico nell'usare altre librerie. Le biblioteche sono semplici big bag di funzioni che puoi chiamare.

Considerati di scrivere una funzione come questa

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

Ora se includi quel file puoi scrivere addExclamation(myVeryOwnString); . Ora potresti chiedere: "come ha fatto improvvisamente C ++ ad aggiungere la possibilità di aggiungere punti esclamativi a una stringa?" La risposta è semplice: hai scritto una funzione per farlo e poi l'hai chiamata.

Quindi, per rispondere alla tua domanda su come C ++ può ottenere funzionalità per disegnare finestre attraverso librerie scritte in C ++, la risposta è la stessa. Qualcun altro ha scritto funzioni per farlo, quindi le ha compilate e te le ha date sotto forma di libreria.

Le altre domande rispondono a come funziona effettivamente il disegno della finestra, ma sembravi confuso su come funzionano le biblioteche, quindi volevo affrontare la parte più fondamentale della tua domanda.


8

La chiave è la possibilità del sistema operativo di esporre un'API e una descrizione dettagliata su come utilizzare questa API.

Il sistema operativo offre un set di API con convenzioni di chiamata. La convenzione di chiamata definisce il modo in cui viene fornito un parametro nell'API e come vengono restituiti i risultati e come eseguire la chiamata effettiva.

I sistemi operativi e i compilatori che creano codice per loro funzionano bene insieme, quindi di solito non devi pensarci, basta usarlo.


7

Non è necessaria una sintassi speciale per la creazione di Windows. Tutto ciò che serve è che il sistema operativo fornisca un'API per creare finestre. Tale API è costituita da semplici chiamate di funzione per le quali C ++ fornisce la sintassi.

Inoltre C e C ++ sono i cosiddetti linguaggi di programmazione dei sistemi e sono in grado di accedere a puntatori arbitrari (che potrebbero essere mappati su alcuni dispositivi dall'hardware). Inoltre, è anche abbastanza semplice chiamare funzioni definite in assembly, che consente l'intera gamma di operazioni fornite dal processore. Pertanto è possibile scrivere un SO stesso usando C o C ++ e una piccola quantità di assembly.

Va anche detto che Qt è un cattivo esempio, in quanto utilizza un cosiddetto meta-compilatore per estendere la sintassi di C ++. Questo non è tuttavia correlato alla sua capacità di chiamare le API fornite dal sistema operativo per disegnare o creare finestre.


7

Innanzitutto, penso che ci sia un po 'di incomprensione

Come funziona C ++, che in precedenza non aveva una sintassi in grado di chiedere al sistema operativo una finestra o un modo per comunicare attraverso le reti

Non esiste sintassi per l'esecuzione delle operazioni del sistema operativo. È la questione della semantica .

improvvisamente ottenere tali capacità attraverso le librerie scritte in C ++ stesse

Bene, il sistema operativo è scritto principalmente in C. Puoi usare librerie condivise (quindi, dll) per chiamare il codice esterno. Inoltre, il codice del sistema operativo può registrare routine di sistema su syscalls * o interruzioni che è possibile chiamare tramite assembly . Quelle librerie condivise spesso fanno solo chiamate di sistema per te, quindi sei risparmiato usando l'assemblaggio in linea.

Ecco il bel tutorial su questo: http://www.win.tue.nl/~aeb/linux/lk/lk-4.html
È per Linux, ma i principi sono gli stessi.

In che modo il sistema operativo sta eseguendo operazioni su schede grafiche, schede di rete ecc.? È un tema molto ampio, ma per lo più è necessario accedere a interrupt, porte o scrivere alcuni dati in un'area di memoria speciale. Poiché tali operazioni sono protette, è comunque necessario chiamarle tramite il sistema operativo.


7

Nel tentativo di fornire una visione leggermente diversa alle altre risposte, risponderò in questo modo.

(Dichiarazione di non responsabilità: sto semplificando leggermente le cose, la situazione che do è puramente ipotetica ed è scritta come mezzo per dimostrare concetti piuttosto che essere fedele al 100% alla vita).

Pensa alle cose dall'altra prospettiva, immagina di aver appena scritto un semplice sistema operativo con funzionalità di threading, windowing e gestione della memoria di base. Volete implementare una libreria C ++ per consentire agli utenti di programmare in C ++ e fare cose come creare finestre, disegnare su Windows ecc. La domanda è: come farlo.

Innanzitutto, poiché il C ++ viene compilato in base al codice macchina, è necessario definire un modo per utilizzare il codice macchina per interfacciarsi con il C ++. È qui che entrano in gioco le funzioni, le funzioni accettano argomenti e danno valori di ritorno, quindi forniscono un modo standard per trasferire dati tra diverse sezioni di codice. Lo fanno stabilendo qualcosa noto come convenzione di chiamata .

Una convenzione di chiamata indica dove e come gli argomenti devono essere collocati in memoria in modo che una funzione possa trovarli quando viene eseguita. Quando viene chiamata una funzione, la funzione chiamante inserisce gli argomenti in memoria e quindi chiede alla CPU di passare all'altra funzione, dove fa quello che fa prima di tornare da dove è stata chiamata. Ciò significa che il codice chiamato può essere assolutamente qualsiasi cosa e non cambierà il modo in cui viene chiamata la funzione. In questo caso, tuttavia, il codice dietro la funzione sarebbe rilevante per il sistema operativo e opererebbe sullo stato interno del sistema operativo.

Quindi, molti mesi dopo e hai sistemato tutte le funzioni del tuo sistema operativo. Il tuo utente può chiamare funzioni per creare finestre e disegnare su di esse, può creare discussioni e ogni sorta di cose meravigliose. Questo è il problema, tuttavia, le funzioni del tuo sistema operativo saranno diverse dalle funzioni di Linux o di Windows. Quindi decidi che devi fornire all'utente un'interfaccia standard in modo che possano scrivere codice portatile. Qui è dove entra in gioco QT.

Come quasi sicuramente saprai, QT ha molte classi e funzioni utili per fare il genere di cose che fanno i sistemi operativi, ma in un modo che sembra indipendente dal sistema operativo sottostante. Il modo in cui funziona è che QT fornisce classi e funzioni uniformi nel modo in cui appaiono all'utente, ma il codice dietro le funzioni è diverso per ogni sistema operativo. Ad esempio, QApplication :: closeAllWindows () di QT chiamerebbe effettivamente la funzione di chiusura della finestra specializzata di ciascun sistema operativo a seconda della versione utilizzata. In Windows molto probabilmente chiamerebbe CloseWindow (hwnd) mentre su un sistema operativo che utilizza X Window System, potenzialmente chiamerebbe XDestroyWindow (display, finestra).

Come è evidente, un sistema operativo ha molti livelli, che devono interagire attraverso interfacce di molte varietà. Ci sono molti aspetti che non ho nemmeno toccato, ma spiegarli tutti richiederebbe molto tempo. Se sei ulteriormente interessato al funzionamento interno dei sistemi operativi, ti consiglio di dare un'occhiata al wiki del dev del sistema operativo .

Tenete presente, tuttavia, che la ragione per cui molti sistemi operativi scelgono di esporre le interfacce in C / C ++ è che si compilano in base al codice macchina, permettono alle istruzioni di assemblaggio di essere mescolate con il proprio codice e offrono un grande grado di libertà al programmatore.

Ancora una volta, c'è molto da fare qui. Vorrei continuare a spiegare come le librerie come i file .so e .dll non debbano essere scritte in C / C ++ e possano essere scritte in assembly o in altre lingue, ma sento che se ne aggiungessi altre potrei anche scrivere un intero articolo e per quanto mi piacerebbe fare non ho un sito su cui ospitarlo.


6

Quando provi a disegnare qualcosa sullo schermo, il tuo codice chiama qualche altro pezzo di codice che chiama qualche altro codice (ecc.) Fino a quando finalmente non c'è una "chiamata di sistema", che è un'istruzione speciale che la CPU può eseguire. Queste istruzioni possono essere scritte in assembly o possono essere scritte in C ++ se il compilatore supporta i loro "intrinseci" (che sono funzioni che il compilatore gestisce "appositamente" convertendole in codice speciale che la CPU può comprendere). Il loro compito è di dire al sistema operativo di fare qualcosa.

Quando si verifica una chiamata di sistema, viene chiamata una funzione che chiama un'altra funzione (ecc.) Fino a quando non viene infine detto al driver del display di disegnare qualcosa sullo schermo. A quel punto, il driver di visualizzazione guarda una particolare regione nella memoria fisica che in realtà non è memoria, ma piuttosto un intervallo di indirizzi in cui è possibile scrivere come se fosse memoria. Invece, scrivendo in quell'intervallo di indirizzi, l' hardware grafico intercetta la scrittura in memoria e disegna qualcosa sullo schermo.
Scrivere in questa regione di memoria è qualcosa che potrebbe essere codificato in C ++, poiché dal lato software è solo un normale accesso alla memoria. È solo che l'hardware lo gestisce in modo diverso.
Quindi questa è una spiegazione davvero basilare di come può funzionare.


4
Dopotutto, una chiamata di sistema non è in realtà un'istruzione cpu e non ha nulla a che fare con gli intrinseci. È più una funzione del kernel del sistema operativo, che comunica con i dispositivi.
MatthiasB,

3
@MatthiasB: Beh, ti sbagli, poiché syscall(e suo cugino sysenter) è davvero un'istruzione CPU.
user541686,

2
Questo è stato solo un suggerimento per migliorare la tua risposta, in quanto non era chiaro per me stesso. Non vederlo come un attacco personale o altro.
MatthiasB,

1
@MatthiasB: non lo prendo sul personale. Sto dicendo che so già che la risposta non è in realtà accurata al 100%, ma penso che sia una buona semplificazione sufficiente per rispondere all'OP - quindi, se in realtà conosci un modo per scrivere una risposta migliore, per favore o scrivi la tua rispondi o prenditi il ​​tempo per modificare il mio. Non ho davvero niente da aggiungere che penso valga la pena, quindi se vuoi vedere qualcosa di meglio in questa pagina dovrai impegnarti da solo.
user541686,

3
Le chiamate di sistema vengono eseguite utilizzando gli interrupt software. Istruzioni come sysentersono percorsi di chiamata ottimizzati, poiché il cambio di contesto utilizzato dai gestori di interrupt non è stato veloce come tutti desideravano, ma fondamentalmente è ancora un interruzione generata da software mentre viene gestita da un gestore installato dal kernel del sistema operativo. Parte del processo di commutazione del contesto che IS esegue sysenterconsiste nel modificare i bit di modalità nel processore per impostare l'anello 0 - accesso completo a tutte le istruzioni privilegiate, i registri e le aree di memoria e I / O.
Ben Voigt,

4

Il tuo programma C ++ utilizza la libreria Qt (anch'essa codificata in C ++). La libreria Qt utilizzerà la funzione Windows CreateWindowEx (che è stata codificata in C all'interno di kernel32.dll). O sotto Linux potrebbe usare Xlib (anch'esso codificato in C), ma potrebbe anche inviare byte grezzi che nel protocollo X significano " Per favore, crea una finestra per me ".

Relativa alla tua domanda catch-22 è la nota storica che "il primo compilatore C ++ è stato scritto in C ++", sebbene in realtà fosse un compilatore C con alcune nozioni C ++, abbastanza da poter compilare la prima versione, che poteva quindi compilarsi .

Allo stesso modo, il compilatore GCC utilizza estensioni GCC: viene prima compilato in una versione, quindi utilizzato per ricompilarsi. (Istruzioni per la creazione di GCC)


2

Come vedo la domanda questa è in realtà una domanda del compilatore.

Guardalo in questo modo, scrivi un pezzo di codice in Assembly (puoi farlo in qualsiasi lingua) che traduce la tua lingua appena scritta che vuoi chiamare Z ++ in Assembly, per semplicità puoi chiamarlo un compilatore (è un compilatore) .

Ora date a questo compilatore alcune funzioni di base, in modo da poter scrivere int, string, array ecc. In realtà gli date abbastanza capacità da poter scrivere il compilatore stesso in Z ++. e ora hai un compilatore per Z ++ scritto in Z ++, piuttosto pulito.

Ciò che è ancora più interessante è che ora puoi aggiungere abilità a quel compilatore usando le abilità che già ha, espandendo così il linguaggio Z ++ con nuove funzionalità usando le funzionalità precedenti

Un esempio, se scrivi abbastanza codice per disegnare un pixel in qualsiasi colore, puoi espanderlo usando Z ++ per disegnare tutto quello che vuoi.


0

L'hardware è ciò che consente che ciò accada. Puoi pensare alla memoria grafica come a un grande array (costituito da ogni pixel sullo schermo). Per disegnare sullo schermo è possibile scrivere su questa memoria usando C ++ o qualsiasi lingua che consenta l'accesso diretto a quella memoria. Quella memoria sembra essere accessibile o situata sulla scheda grafica.

Sui sistemi moderni l'accesso diretto alla memoria grafica richiederebbe la scrittura di un driver a causa di varie restrizioni in modo da utilizzare mezzi indiretti. Librerie che creano una finestra (in realtà solo un'immagine come qualsiasi altra immagine) e quindi scrivono quell'immagine nella memoria grafica che la GPU visualizza sullo schermo. Nulla deve essere aggiunto alla lingua tranne la possibilità di scrivere in posizioni di memoria specifiche, che è ciò che serve per i puntatori.


Il punto che stavo cercando di evidenziare è che una lingua non ha bisogno di "espandersi" nel senso che una nuova versione della lingua deve essere riscritta e che non è davvero circolare dal momento che per fare qualcosa di interessante un programma deve interfacciarsi con l'hardware.
Giovanni,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.