Je me demandais comment Scanf () / Printf () fonctionne réellement dans les niveaux de matériel et de système d'exploitation. Où le flux de données et quel est exactement le système d'exploitation autour de ces temps? Quels appels le système d'exploitation fait-il? Et ainsi de suite ... p>
4 Réponses :
Je pense que le système d'exploitation fournit simplement deux flux, un pour l'entrée et l'autre pour la sortie, les flux abstraites de la manière dont les données de sortie sont présentées ou lorsque les données d'entrée proviennent. P>
Alors, quels scanf & Printf font simplement ajouter des octets (ou consommer des octets) à partir des flux. P>
C'est l'abstraction de haut niveau. Je souhaite connaître les détails de la manière dont ces flux fonctionnent avec le matériel et la façon dont le système d'exploitation gère toutes les données.
scanf () et printf () sont des fonctions dans Libc (la bibliothèque standard C), et ils appellent respectivement les syscalls d'exploitation de lecture () et d'écriture () et d'écriture (), de conversation respectivement (FSCANF et FPRRINTF Vous permet de spécifier le flux de fichiers que vous souhaitez lire / écrire de). p>
Appels pour lire () et écrire () (et tous les systèmes SysCalls) entraînent un «commutateur contextuel» de votre application au niveau de l'utilisateur en mode noyau, ce qui signifie qu'il peut effectuer des opérations privilégiées, telles que parler directement au matériel. Selon la manière dont vous avez démarré l'application, les descripteurs de fichiers «stdin» et «stdout» sont probablement liés à un périphérique de console (telle que TTY0), ou une sorte de dispositif de console virtuel (comme celui exposé par un xterm). Lire () et écrire () Copier les données en toute sécurité sur / depuis un tampon de noyau appelé "UIO". P>
La partie de conversion de chaîne de format de SCANF et PrintF ne se produit pas en mode noyau, mais juste en mode utilisateur ordinaire (à l'intérieur 'libc'), la règle générale de SysCalls est votre position de noyau aussi rarement que possible. , les deux pour éviter la surcharge de performance du changement de contexte et pour la sécurité (vous devez faire très attention à tout ce qui se passe en mode noyau! Moins de code en mode noyau signifie moins de bogues / de trous de sécurité dans le système d'exploitation). P>
BTW .. Tout cela a été écrit à partir d'une perspective UNIX, je ne sais pas comment fonctionne Mme Windows. P>
Le changement de contexte sonne lentement s'il lit chaque octet individuellement. Bien sûr, cela n'a pas vraiment d'importance en ce jour et à l'âge, mais je suis juste intéressé à savoir si je suis correct dans cette compréhension.
Les syscalls de lecture et d'écriture prennent un certain nombre d'octets pour transférer via les paramètres UIO en tant que paramètres. Il ne doit donc pas nécessairement faire une syscall distincte pour chaque octet. Vous penseriez également que pour des fonctions de saisie plus simples telles que GetChartar (), il faudrait être un appel distinct pour chaque personnage, mais en fait, Libc est un peu intelligent que cela et qu'il conserve un tampon (à l'intérieur de la libc). Il peut donc éviter la surcharge de performance du contexte basculant de beaucoup en remplissant la mémoire tampon, puis le traitement d'un peu de cela chaque fois que vous getchar () ou Scanf (), jusqu'à ce que la mémoire tampon soit vide et que ce soit simplement un autre syscall.
Sur le sujet de "Cela n'a pas vraiment d'importance en ce jour un âge", vous seriez en fait surpris de savoir à quel point les systèmes SysCalls auraient considérablement une incidence sur la performance. Considérez que SysCalls est au moins i> 10 fois plus tard comme un appel de fonction régulier. Si vous avez un tampon de taille 1024 octets, par exemple, vous ne faites que 1/1024 autant de syscalls. Écrire une implémentation C de la commande «CP» avec et sans tampon est un excellent exemple, je le posterai dans quelques minutes.
Je ne sais pas non plus comment Mada Windows fonctionne non plus. Non sérieusement. C'est un miracle ça marche du tout :-)
Wow, cela semble bon. Comment le système d'exploitation transfère-t-il les octets du clavier sur sa mémoire tampon UIO? Les appels Lire () et écrire () le font, mais d'où? Où les octets viennent-ils du clavier? Le pilote de clavier?
Lire () Je ne sais pas sur le clavier, il est à une couche d'abstraction légèrement supérieure, elle connaît simplement le nœud de l'appareil qu'il parle, tel qu'un dispositif de console. Le pilote de cet appareil fournira un nœud dans le système de fichiers qui lisent () peut parler à et c'est le conducteur qui doit être capable de sortir des caractères du matériel.
Ah Ok, je vois la grande image maintenant. Merci David! :)
Juste un détail - il n'est pas sûr de supposer que lire () / écriture () sont utilisés en interne. Pour une, elles sont des fonctions POSIX et, en tant que telles, ne font pas partie de la norme C. Selon la plate-forme, des fonctions de bas niveau différentes peuvent être appelées.
@DevSolar, absolument, j'utilisais simplement un système de Linux typique à titre d'exemple.
Heureusement pour la performance de beaucoup de Code C simple, STDIO fonctionne comme scanf code> et
printf code> N'appelez pas
lire code> ou
écrire < / code> à chaque fois. Ils (généralement, je simplifie) réellement gérer un tampon qu'ils remplissent avec l'appel du système aussi rarement que possible pour réduire le nombre d'interrupteurs et hors du noyau. Une implémentation typique de Windows Libc fonctionne beaucoup de la même manière, mais utilise le
lishfile code> et
wriersfile code> appels système. Les détails à l'intérieur du noyau sont différents, mais les abstractions de base et le flux de données globales sont très similaires.
@DevSolar ofcourse, il diffère basé sur la plate-forme. * Nix est juste un bon endroit pour commencer. Je voulais juste que l'idée. Ce serait cool si quelqu'un pouvait ajouter des détails sur ce que fait le système d'exploitation et ce que les pilotes font à un niveau plus bas. :)
@ jetru - scanf () est totalement ignorant de ce que font les niveaux inférieurs du système d'exploitation. C'est juste une enveloppe pour FSCANF (STDIN, ...). Cela peut être mis en œuvre en termes d'appels Fgec (). Cette fonction, à son tour, se lit dans le tampon de flux et si le tampon est épuisé, déclenche une fonction spécifique au système d'exploitation pour reconstituer le tampon. (Sur les systèmes POSIX, lisez ().) Quelle fonction fonctionne, au niveau du conducteur ... en fonction du type de flux (fichier, terminal) et au noyau du système d'exploitation, et serait un problème que si vous voulez faire os i> développement. Y a-t-il des questions spécifiques i> que vous avez là-bas?
@DavidClaridge: très belle réponse. Je veux savoir comment ils travaillent sur MS Windows OS.
sur mon système d'exploitation, je travaille avec Scanf et Printf sont basés sur les fonctions GetCH () Putch (). P>
Wow c'était quelque chose. J'ai réussi à modifier la sortie de UART en TCP / IP lorsqu'il y avait un client unique connecté. C'était simple microkernel coopératif non préventif pour système embarqué.
scanf, printf, etc., tous ces types de fonctions ne peuvent pas être directement écrits en langage C / C ++. En interne, ils sont tous écrits dans la langue d'assemblage forte> par l'utilisation de
De quel système d'exploitation parlez-vous?
Je ne regarde aucun système d'exploitation particulier. Les types Linux / Unix seraient tout simplement bien. Je veux juste une compréhension de base de la situation.
Ils ne font généralement pas partie du système d'exploitation - mais une partie de la bibliothèque C (Libc, Glibc, ...). SCANF () utilise la lecture de POSIX () et PrintF l'écriture de POSIX () finalement. Certains livres de programmation Unix standard devraient aider à ce niveau tel que la programmation avancée dans l'environnement UNIX (APUE).