C (langage de programmation)
C ( / ˈ s iː / , comme dans la lettre c ) est un langage de programmation informatique à usage général . Il a été créé dans les années 1970 par Dennis Ritchie , et reste très largement utilisé et influent. De par leur conception, les fonctionnalités de C reflètent clairement les capacités des processeurs ciblés. Il a trouvé une utilisation durable dans les systèmes d’exploitation , les pilotes de périphériques , les piles de protocoles , bien que de moins en moins pour les logiciels d’application , et est courant dans les architectures informatiques allant des plus grands superordinateurs aux plus petits microcontrôleurs.et les systèmes embarqués .
Le langage de programmation C [1] | |
Paradigme | Multi-paradigme : impératif ( procédural ), structuré |
---|---|
Conçu par | Denis Ritchie |
Développeur | ANSI X3J11 ( ANSI C ); ISO/CEI JTC1 (Comité technique mixte 1) / SC22 (Sous-comité 22) / WG14 (Groupe de travail 14) (ISO C) |
Première apparition | 1972 ; il y a 50 ans [2] ( 1972 ) |
Version stable | C17 / juin 2018 ; il y a 3 ans ( 2018-06 ) |
Version d’aperçu | C2x ( N2731 ) / 18 octobre 2021 ; il y a 6 mois [3] ( 2021-10-18 ) |
Discipline de frappe | Statique , faible , manifeste , nominal |
SE | Multiplateforme |
Extensions de nom de fichier | .c, .h |
Site Internet | www .iso .org /standard /74528 .html www .open-std .org /jtc1 /sc22 /wg14 / |
Principales implémentations | |
pcc , GCC , Clang , Intel C , C++Builder , Microsoft Visual C++ , Watcom C | |
Dialectes | |
Cyclone , Unified Parallel C , Split-C , Cilk , C* | |
Influencé par | |
B ( BCPL , CPL ), ALGOL 68 , [4] assemblage , PL/I , Fortran | |
Influencé | |
Nombreux : AMPL , AWK , csh , C++ , C– , C# , Objective-C , D , Go , Java , JavaScript , JS++ , Julia , Limbo , LPC , Perl , PHP , Pike , Processing , Python , Rust , Seed7 , Vala , Verilog (HDL), [5] Nim, Zig | |
|
Successeur du langage de programmation B , C a été initialement développé aux Bell Labs par Dennis Ritchie entre 1972 et 1973 pour construire des utilitaires fonctionnant sous Unix . Il a été appliqué à la réimplémentation du noyau du système d’exploitation Unix. [6] Au cours des années 1980, C a progressivement gagné en popularité. Il est devenu l’un des langages de programmation les plus largement utilisés , [7] [8] avec des compilateurs C disponibles pour presque toutes les architectures informatiques et systèmes d’exploitation modernes. C est normalisé par ANSI depuis 1989 ( ANSI C ) et par laOrganisation internationale de normalisation (ISO).
C est un langage procédural impératif prenant en charge la programmation structurée , la portée des variables lexicales et la récursivité , avec un Système de type statique . Il a été conçu pour être compilé afin de fournir un accès de bas niveau à la mémoire et aux constructions de langage qui correspondent efficacement aux instructions machine , le tout avec une prise en charge minimale de l’exécution . Malgré ses capacités de bas niveau, le langage a été conçu pour encourager la programmation Multiplateforme. Un programme C conforme aux standards écrit avec portabilitéà l’esprit peut être compilé pour une grande variété de plates-formes informatiques et de systèmes d’exploitation avec peu de changements à son code source. [9]
Depuis 2000, C s’est régulièrement classé parmi les deux premiers langages de l’ indice TIOBE , une mesure de la popularité des langages de programmation. [dix]
Aperçu
Dennis Ritchie (à droite), l’inventeur du langage de programmation C, avec Ken Thompson
C est un langage procédural impératif dans la tradition ALGOL . Il a un Système de type statique . En C, tout le Code exécutable est contenu dans des sous- programmes (également appelés “fonctions”, mais pas au sens de la programmation fonctionnelle ). Les paramètres de fonction sont passés par valeur, bien que les tableaux soient passés sous forme de pointeurs , c’est-à-dire l’adresse du premier élément du tableau. Le passage par référence est simulé en C en passant explicitement des pointeurs vers la chose référencée.
Le texte source du programme C est au format libre , utilisant le point- virgule comme séparateur d’ instructions et des Accolades pour regrouper les Blocs d’instructions .
Le langage C présente également les caractéristiques suivantes :
- Le langage a un petit nombre fixe de mots-clés, y compris un ensemble complet de primitives de flux de contrôleif/else : , for, do/while, while, et switch. Les noms définis par l’utilisateur ne se distinguent des mots-clés par aucun type de sceau .
- Il possède un grand nombre d’opérateurs arithmétiques, binaires et logiques : +, +=, ++, &, ||, etc.
- Plus d’une tâche peut être effectuée dans une seule instruction.
- Les fonctions:
- Les valeurs de retour de fonction peuvent être ignorées, lorsqu’elles ne sont pas nécessaires.
- Les pointeurs de fonction et de données permettent un Polymorphisme d’exécution ad hoc .
- Les fonctions ne peuvent pas être définies dans le cadre lexical d’autres fonctions.
- Les variables peuvent être définies dans une fonction, avec une portée .
- Une fonction peut s’appeler elle-même, la récursivité est donc prise en charge.
- Le typage des données est statique , mais faiblement appliqué ; toutes les données ont un type, mais des conversions implicites sont possibles.
- Les types définis par l’utilisateur ( typedef ) et composés sont possibles.
- Les types de données agrégées hétérogènes ( struct) permettent d’accéder aux éléments de données connexes et de les affecter en tant qu’unité.
- L’Union est une structure avec des membres qui se chevauchent; seul le dernier membre stocké est valide.
- L’indexation de tableau est une notation secondaire, définie en termes d’arithmétique de pointeur. Contrairement aux structures, les tableaux ne sont pas des objets de première classe : ils ne peuvent pas être affectés ou comparés à l’aide d’opérateurs intégrés uniques. Il n’y a pas de mot-clé “array” en cours d’utilisation ou de définition ; à la place, les crochets indiquent des tableaux syntaxiquement, par exemple month[11].
- Les types énumérés sont possibles avec le mot- enumclé. Ils sont librement interconvertibles avec des nombres entiers.
- Les chaînes ne sont pas un type de données distinct, mais sont classiquement implémentées sous forme de tableaux de caractères à terminaison nulle .
- L’accès de bas niveau à la mémoire de l’ordinateur est possible en convertissant les adresses machine en pointeurs .
- Les procédures (sous-routines ne renvoyant pas de valeurs) sont un cas particulier de fonction, avec un type de retour non typé void.
- La mémoire peut être allouée à un programme avec des appels à des routines de bibliothèque .
- Un préprocesseur effectue la définition de la macro , l’inclusion du fichier de code source et la compilation conditionnelle .
- Il existe une forme de base de modularité : les fichiers peuvent être compilés séparément et liés entre eux, avec un contrôle sur les fonctions et les objets de données qui sont visibles pour les autres fichiers via staticet les externattributs.
- Les fonctionnalités complexes telles que les E/S , la manipulation de chaînes et les fonctions mathématiques sont systématiquement déléguées aux routines de la bibliothèque .
- Le code généré après compilation a des besoins relativement simples sur la plate-forme sous-jacente, ce qui le rend adapté à la création de systèmes d’exploitation et à une utilisation dans des systèmes embarqués.
Bien que C n’inclue pas certaines fonctionnalités trouvées dans d’autres langages (telles que l’orientation objet et le ramasse -miettes ), celles-ci peuvent être implémentées ou émulées, souvent grâce à l’utilisation de bibliothèques externes (par exemple, le système d’objets GLib ou le ramasse-miettes Boehm ).
Relations avec les autres langues
De nombreux langages ultérieurs ont emprunté directement ou indirectement à C, notamment C++ , C# , le shell C d’Unix , D , Go , Java , JavaScript (y compris les transpilers ), Julia , Limbo , LPC , Objective-C , Perl , PHP , Python , Ruby , Rust , Swift , Verilog et SystemVerilog (langages de description de matériel). [5]Ces langages ont tiré bon nombre de leurs structures de contrôle et d’autres fonctionnalités de base de C. La plupart d’entre eux (Python étant une exception dramatique) expriment également une syntaxe très similaire à C, et ils ont tendance à combiner l’expression reconnaissable et la syntaxe d’instruction de C avec le type sous-jacent . des systèmes, des modèles de données et une sémantique qui peuvent être radicalement différents.
Histoire
Premiers développements
An | Norme C [9] |
---|---|
1972 | Naissance |
1978 | K&R C |
1989/1990 | ANSI C et ISO C |
1999 | C99 |
2011 | C11 |
2017 | C17 |
À déterminer | C2x |
L’origine de C est étroitement liée au développement du système d’exploitation Unix , initialement implémenté en langage assembleur sur un PDP-7 par Dennis Ritchie et Ken Thompson, incorporant plusieurs idées de collègues. Finalement, ils ont décidé de porter le système d’exploitation sur un PDP-11 . La version originale PDP-11 d’Unix a également été développée en langage d’assemblage. [6]
B
Thompson souhaitait un langage de programmation pour créer des utilitaires pour la nouvelle plate-forme. Au début, il a essayé de faire un compilateur Fortran , mais a rapidement abandonné l’idée. Au lieu de cela, il a créé une version réduite du langage de programmation des systèmes BCPL récemment développé . La description officielle de BCPL n’était pas disponible à l’époque [11] et Thompson a modifié la syntaxe pour qu’elle soit moins verbeuse et similaire à un ALGOL simplifié connu sous le nom de SMALGOL. [12] Le résultat a été ce que Thompson a appelé B . [6] Il a décrit B comme “la sémantique BCPL avec beaucoup de syntaxe SMALGOL”. [12] Comme BCPL , B avait un bootstrapcompilateur pour faciliter le portage vers de nouvelles machines. [12] Cependant, peu d’utilitaires ont finalement été écrits en B car il était trop lent et ne pouvait pas tirer parti des fonctionnalités de PDP-11 telles que l’ adressabilité des octets .
Nouvelle version B et première version C
En 1971, Ritchie a commencé à améliorer B, pour utiliser les fonctionnalités du PDP-11 plus puissant. Un ajout important était un type de caractère. Il a appelé ce nouveau B . [12] Thompson a commencé à utiliser NB pour écrire le noyau Unix et ses exigences ont façonné la direction du développement du langage. [12] [13] Jusqu’en 1972, des types plus riches ont été ajoutés au langage NB : NB avait des tableaux de intet char; mais ensuite ont été ajoutés des pointeurs, la possibilité de générer des pointeurs vers d’autres types, des tableaux de tous ces types, des types à renvoyer à partir des fonctions. Les tableaux dans les expressions sont devenus des pointeurs. Un nouveau compilateur a été écrit et le langage a été renommé C. [6]
Le compilateur C et certains utilitaires créés avec lui ont été inclus dans la version 2 d’Unix . [14]
Structures et réécriture du noyau Unix
À la version 4 Unix , publiée en novembre 1973, le noyau Unix a été largement réimplémenté en C. [6] À cette époque, le langage C avait acquis des fonctionnalités puissantes telles que les types.struct
Le préprocesseur a été introduit vers 1973 à la demande d’ Alan Snyder et également en reconnaissance de l’utilité des mécanismes d’inclusion de fichiers disponibles dans BCPL et PL/I. Sa version originale ne fournissait que des fichiers inclus et de simples remplacements de chaînes : #includeet #definede macros sans paramètres. Peu de temps après, il a été étendu, principalement par Mike Lesk puis par John Reiser, pour incorporer des macros avec des arguments et une compilation conditionnelle. [6]
Unix a été l’un des premiers noyaux de systèmes d’exploitation implémentés dans un langage autre que l’assembleur . Les exemples antérieurs incluent le système Multics (qui a été écrit en PL / I ) et le programme de contrôle principal (MCP) pour le Burroughs B5000 (qui a été écrit en ALGOL ) en 1961. Vers 1977, Ritchie et Stephen C. Johnson ont apporté d’autres modifications à le langage pour faciliter la portabilité du système d’exploitation Unix. Le compilateur C portable de Johnson a servi de base à plusieurs implémentations de C sur de nouvelles plates-formes. [13]
K&R C
La couverture du livre The C Programming Language , première édition, de Brian Kernighan et Dennis Ritchie
En 1978, Brian Kernighan et Dennis Ritchie ont publié la première édition de The C Programming Language . [1] Ce livre, connu des programmeurs C sous le nom de K&R , a servi pendant de nombreuses années de spécification informelle du langage. La version de C qu’il décrit est communément appelée ” K&R C “. Comme il a été publié en 1978, il est également appelé C78 . [15] La deuxième édition du livre [16] couvre la dernière norme ANSI C , décrite ci-dessous.
K&R a introduit plusieurs fonctionnalités linguistiques :
- Bibliothèque d’E/S standard
- long intType de données
- unsigned intType de données
- Les opérateurs d’affectation composés de la forme (tels que ) ont été remplacés par la forme (c’est-à-dire ) pour supprimer l’ambiguïté sémantique créée par des constructions telles que , qui avaient été interprétées comme (décrémenter de 10) au lieu de l’éventuelle intention ( soit – dix).=op=-op=-=i=-10i =- 10ii = -10i
Même après la publication de la norme ANSI de 1989, pendant de nombreuses années, K&R C était encore considéré comme le ” plus petit dénominateur commun ” auquel les programmeurs C se limitaient lorsqu’une portabilité maximale était souhaitée, car de nombreux compilateurs plus anciens étaient encore utilisés, et parce que K&R soigneusement écrit Le code C peut également être la norme C légale.
Dans les premières versions de C, seules les fonctions qui renvoient des types autres que intdoivent être déclarées si elles sont utilisées avant la définition de la fonction ; les fonctions utilisées sans déclaration préalable étaient supposées renvoyer type int.
Par example:
long some_function (); /* entier */ autre_fonction (); /* int */ fonction_appelante () { essai long1 ; registre /* int */ test2 ; test1 = some_function (); si ( test1 > 1 ) essai2 = 0 ; autre test2 = autre_fonction (); renvoie test2 ; }
Les intspécificateurs de type qui sont commentés pourraient être omis dans K&R C, mais sont requis dans les normes ultérieures.
Étant donné que les déclarations de fonction K&R n’incluaient aucune information sur les arguments de fonction, les vérifications de type de paramètre de fonction n’étaient pas effectuées, bien que certains compilateurs émettaient un message d’avertissement si une fonction locale était appelée avec le mauvais nombre d’arguments, ou si plusieurs appels à une fonction externe utilisé différents nombres ou types d’arguments. Des outils distincts tels que l’ utilitaire lint d’Unix ont été développés qui (entre autres) pourraient vérifier la cohérence de l’utilisation des fonctions dans plusieurs fichiers source.
Dans les années qui ont suivi la publication de K&R C, plusieurs fonctionnalités ont été ajoutées au langage, prises en charge par des compilateurs d’AT&T (en particulier PCC [17] ) et d’autres fournisseurs. Celles-ci comprenaient :
- voidles fonctions (c’est-à-dire les fonctions sans valeur de retour)
- fonctions renvoyant structou uniontypes (plutôt que des pointeurs)
- affectation pour structles types de données
- types énumérés
Le grand nombre d’extensions et le manque d’accord sur une bibliothèque standard , ainsi que la popularité du langage et le fait que même les compilateurs Unix n’ont pas implémenté précisément la spécification K&R, ont conduit à la nécessité d’une standardisation. [ citation nécessaire ]
ANSI C et ISO C
À la fin des années 1970 et 1980, des versions de C ont été implémentées pour une grande variété d’ ordinateurs centraux , de mini- ordinateurs et de micro -ordinateurs , y compris l’ IBM PC , alors que sa popularité commençait à augmenter de manière significative.
En 1983, l’ American National Standards Institute (ANSI) a formé un comité, X3J11, pour établir une spécification standard de C. X3J11 a basé la norme C sur l’implémentation Unix; cependant, la partie non portable de la bibliothèque Unix C a été confiée au groupe de travail IEEE 1003 pour devenir la base de la norme POSIX de 1988 . En 1989, la norme C a été ratifiée en tant que ANSI X3.159-1989 “Programming Language C”. Cette version du langage est souvent appelée ANSI C , Standard C ou parfois C89.
En 1990, la norme ANSI C (avec des modifications de format) a été adoptée par l’ Organisation internationale de normalisation (ISO) sous le nom d’ISO/IEC 9899:1990, parfois appelée C90. Par conséquent, les termes “C89” et “C90” font référence au même langage de programmation.
L’ANSI, comme d’autres organismes nationaux de normalisation, ne développe plus la norme C de manière indépendante, mais s’en remet à la norme C internationale, maintenue par le groupe de travail ISO/IEC JTC1/SC22 /WG14. L’adoption nationale d’une mise à jour de la norme internationale se produit généralement dans l’année suivant la publication de l’ISO.
L’un des objectifs du processus de normalisation C était de produire un sur- ensemble de K&R C, incorporant de nombreuses fonctionnalités non officielles introduites par la suite. Le comité des normes a également inclus plusieurs fonctionnalités supplémentaires telles que des prototypes de fonctions (empruntés à C++), voiddes pointeurs, la prise en charge des jeux de caractères et des paramètres régionaux internationaux et des améliorations du préprocesseur. Bien que la syntaxe des déclarations de paramètres ait été augmentée pour inclure le style utilisé en C++, l’interface K&R a continué d’être autorisée, pour la compatibilité avec le code source existant.
C89 est pris en charge par les compilateurs C actuels et la plupart des codes C modernes sont basés dessus. Tout programme écrit uniquement en C standard et sans aucune hypothèse dépendante du matériel fonctionnera correctement sur n’importe quelle plate-forme avec une implémentation C conforme, dans les limites de ses ressources. Sans ces précautions, les programmes peuvent compiler uniquement sur une certaine plate-forme ou avec un compilateur particulier, en raison, par exemple, de l’utilisation de bibliothèques non standard, telles que des bibliothèques d’ interface graphique , ou d’une dépendance à des attributs spécifiques au compilateur ou à la plate-forme tels que comme la taille exacte des types de données et l’ endianité en octets .
Dans les cas où le code doit être compilable par des compilateurs conformes à la norme ou basés sur K&R C, la __STDC__macro peut être utilisée pour diviser le code en sections Standard et K&R afin d’empêcher l’utilisation sur un compilateur basé sur K&R C de fonctionnalités disponibles uniquement dans Standard C
Après le processus de normalisation ANSI/ISO, la spécification du langage C est restée relativement statique pendant plusieurs années. En 1995, l’amendement normatif 1 à la norme 1990 C (ISO/IEC 9899/AMD1:1995, connu officieusement sous le nom de C95) a été publié, pour corriger certains détails et ajouter une prise en charge plus étendue des jeux de caractères internationaux. [18]
C99
La norme C a ensuite été révisée à la fin des années 1990, ce qui a conduit à la publication de la norme ISO/IEC 9899:1999 en 1999, communément appelée « C99 ». Il a depuis été modifié à trois reprises par des rectificatifs techniques. [19]
C99 a introduit plusieurs nouvelles fonctionnalités, notamment des fonctions en ligne , plusieurs nouveaux types de données (y compris long long intet un complextype pour représenter des nombres complexes ), des tableaux de longueur variable et des membres de tableau flexibles , une prise en charge améliorée de la virgule flottante IEEE 754 , la prise en charge des macros variadiques (macros de variable arité ) et la prise en charge des commentaires d’une ligne commençant par //, comme dans BCPL ou C++. Beaucoup d’entre eux avaient déjà été implémentés en tant qu’extensions dans plusieurs compilateurs C.
C99 est pour la plupart rétrocompatible avec C90, mais est plus strict à certains égards; en particulier, une déclaration qui n’a pas de spécificateur de type n’a plus intsupposé implicitement. Une macro standard __STDC_VERSION__est définie avec une valeur 199901Lpour indiquer que la prise en charge de C99 est disponible. GCC , Solaris Studio et d’autres compilateurs C prennent désormais en charge la plupart ou la totalité des nouvelles fonctionnalités de C99. Le compilateur C dans Microsoft Visual C++ , cependant, implémente la norme C89 et les parties de C99 qui sont requises pour la compatibilité avec C++11 . [20] [ nécessite une mise à jour ]
De plus, la prise en charge des identifiants Unicode (noms de variables / fonctions) sous forme de caractères d’échappement (par exemple U0001f431) est désormais requise. La prise en charge des noms Unicode bruts est facultative.
C11
En 2007, les travaux ont commencé sur une autre révision de la norme C, officieusement appelée “C1X” jusqu’à sa publication officielle le 2011-12-08. Le comité des normes C a adopté des lignes directrices pour limiter l’adoption de nouvelles fonctionnalités qui n’avaient pas été testées par les implémentations existantes.
La norme C11 ajoute de nombreuses nouvelles fonctionnalités au C et à la bibliothèque, notamment des macros génériques de type, des structures anonymes, une prise en charge améliorée d’Unicode, des opérations atomiques, le multithreading et des fonctions à limites vérifiées. Il rend également certaines parties de la bibliothèque C99 existante facultatives et améliore la compatibilité avec C++. La macro standard __STDC_VERSION__est définie 201112Lpour indiquer que la prise en charge de C11 est disponible.
C17
Publié en juin 2018, C17 est la norme actuelle pour le langage de programmation C. Il n’introduit aucune nouvelle fonctionnalité de langage, uniquement des corrections techniques et des clarifications sur les défauts de C11. La macro standard __STDC_VERSION__est définie comme 201710L.
C2x
C2x est un nom informel pour la prochaine révision majeure du langage C (après C17). Il devrait être voté en 2023 et s’appellerait donc C23. [21] [ meilleure source nécessaire ]
C intégré
Historiquement, la programmation C embarquée nécessite des extensions non standard du langage C afin de prendre en charge des fonctionnalités exotiques telles que l’arithmétique en virgule fixe , plusieurs banques de mémoire distinctes et les opérations d’E/S de base.
En 2008, le C Standards Committee a publié un rapport technique étendant le langage C [22] pour résoudre ces problèmes en fournissant une norme commune à laquelle toutes les implémentations doivent se conformer. Il inclut un certain nombre de fonctionnalités non disponibles en C normal, telles que l’arithmétique en virgule fixe , les espaces d’adressage nommés et l’adressage matériel d’E/S de base.
Syntaxe
C a une grammaire formelle spécifiée par la norme C. [23] Les terminaisons de ligne ne sont généralement pas significatives en C ; cependant, les limites de ligne ont une importance pendant la phase de prétraitement. Les commentaires peuvent apparaître soit entre les délimiteurs /*et */, soit (depuis C99) suivant //jusqu’à la fin de la ligne. Les commentaires délimités par /*et */ne s’imbriquent pas, et ces séquences de caractères ne sont pas interprétées comme des délimiteurs de commentaires si elles apparaissent à l’intérieur de chaînes ou de caractères littéraux. [24]
Les fichiers sources C contiennent des déclarations et des définitions de fonctions. Les définitions de fonction, à leur tour, contiennent des déclarations et des instructions . Les déclarations définissent de nouveaux types à l’aide de mots clés tels que struct, union, et enum, ou attribuent des types à et peut-être réservent du stockage pour de nouvelles variables, généralement en écrivant le type suivi du nom de la variable. Des mots-clés tels que charet intspécifient des types intégrés. Les sections de code sont entourées d’Accolades ( {et }, parfois appelées “Accolades“) pour limiter la portée des déclarations et agir comme une instruction unique pour les structures de contrôle.
En tant que langage impératif, C utilise des instructions pour spécifier des actions. L’instruction la plus courante est une instruction d’expression , composée d’une expression à évaluer, suivie d’un point-virgule ; en tant qu’effet secondaire de l’évaluation, des fonctions peuvent être appelées et des variables peuvent recevoir de nouvelles valeurs. Pour modifier l’exécution séquentielle normale des instructions, C fournit plusieurs instructions de flux de contrôle identifiées par des mots clés réservés. La programmation structurée est prise en charge par if… [ else] exécution conditionnelle et par do… while, while, et forexécution itérative (boucle). LeforL’instruction a des expressions d’initialisation, de test et de réinitialisation distinctes, dont tout ou partie peut être omis. breaket continuepeut être utilisé pour quitter l’instruction de boucle englobante la plus interne ou pour passer à sa réinitialisation. Il existe également une instruction non structurée gotoqui se branche directement sur l’ étiquette désignée dans la fonction. switchsélectionne a caseà exécuter en fonction de la valeur d’une expression entière.
Les expressions peuvent utiliser une variété d’opérateurs intégrés et peuvent contenir des appels de fonction. L’ordre dans lequel les arguments des fonctions et les opérandes de la plupart des opérateurs sont évalués n’est pas spécifié. Les évaluations peuvent même être entrelacées. Cependant, tous les effets secondaires (y compris le stockage dans les variables) se produiront avant le prochain « point de séquence » ; les points de séquence incluent la fin de chaque instruction d’expression, ainsi que l’entrée et le retour de chaque appel de fonction. Des points de séquence se produisent également lors de l’évaluation d’expressions contenant certains opérateurs ( &&, ||, ?:et l’ opérateur virgule). Cela permet un degré élevé d’optimisation du code objet par le compilateur, mais oblige les programmeurs C à prendre plus de soin pour obtenir des résultats fiables que ce qui est nécessaire pour d’autres langages de programmation.
Kernighan et Ritchie disent dans l’introduction du langage de programmation C : “C, comme tout autre langage, a ses défauts. Certains opérateurs ont la mauvaise priorité ; certaines parties de la syntaxe pourraient être meilleures.” [25] La norme C n’a pas tenté de corriger bon nombre de ces défauts, en raison de l’impact de tels changements sur les logiciels déjà existants.
Jeu de caractères
Le jeu de caractères source C de base comprend les caractères suivants :
- Lettres minuscules et majuscules de l’alphabet latin de base ISO : a– z A–Z
- Chiffres décimaux : 0–9
- Caractères graphiques :! ” # % & ‘ ( ) * + , – . / : ; < = > ? [ ] ^ _ { | } ~
- Caractères blancs : espace , tabulation horizontale , tabulation verticale , saut de page , retour à la ligne
La nouvelle ligne indique la fin d’une ligne de texte ; il n’est pas nécessaire qu’il corresponde à un caractère unique réel, bien que pour des raisons pratiques, C le traite comme tel.
Des caractères supplémentaires codés sur plusieurs octets peuvent être utilisés dans les littéraux de chaîne, mais ils ne sont pas entièrement portables . La dernière norme C ( C11 ) permet aux caractères Unicode multinationaux d’être intégrés de manière portable dans le texte source C en utilisant uXXXXou en UXXXXXXXXencodant (où Xdésigne un caractère hexadécimal), bien que cette fonctionnalité ne soit pas encore largement implémentée.
Le jeu de caractères d’exécution C de base contient les mêmes caractères, ainsi que des représentations pour alert , retour arrière et retour chariot . La prise en charge à l’exécution des jeux de caractères étendus a augmenté avec chaque révision de la norme C.
Mots réservés
C89 comporte 32 mots réservés, également appelés mots-clés, qui sont les mots qui ne peuvent être utilisés à d’autres fins que celles pour lesquelles ils sont prédéfinis :
- auto
- break
- case
- char
- const
- continue
- default
- do
- double
- else
- enum
- extern
- float
- for
- goto
- if
- int
- long
- register
- return
- short
- signed
- sizeof
- static
- struct
- switch
- typedef
- union
- unsigned
- void
- volatile
- while
C99 a réservé cinq mots supplémentaires :
- _Bool
- _Complex
- _Imaginary
- inline
- restrict
C11 a réservé sept mots supplémentaires : [26]
- _Alignas
- _Alignof
- _Atomic
- _Generic
- _Noreturn
- _Static_assert
- _Thread_local
La plupart des mots récemment réservés commencent par un trait de soulignement suivi d’une lettre majuscule, car les identifiants de cette forme étaient auparavant réservés par la norme C pour être utilisés uniquement par les implémentations. Étant donné que le code source du programme existant n’aurait pas dû utiliser ces identifiants, il ne serait pas affecté lorsque les implémentations C commenceraient à prendre en charge ces extensions du langage de programmation. Certains en-têtes standard définissent des synonymes plus pratiques pour les identificateurs soulignés. Le langage comprenait auparavant un mot réservé appelé entry, mais celui-ci était rarement implémenté et a maintenant été supprimé en tant que mot réservé. [27]
Les opérateurs
C prend en charge un riche ensemble d’ opérateurs , qui sont des symboles utilisés dans une expression pour spécifier les manipulations à effectuer lors de l’évaluation de cette expression. C a des opérateurs pour :
- arithmétique : +, -, *, /,%
- affectation :=
- affectation augmentée : +=, , , , , , , , , -= *= /= %= &= |= ^= <<= >>=
- logique au niveau du bit : ~, &, |,^
- décalages au niveau du bit : <<,>>
- logique booléenne : !, &&,||
- évaluation conditionnelle 😕 :
- test d’égalité : ==,!=
- fonctions d’appel 🙁 )
- incrémenter et décrémenter : ++,–
- sélection des membres : .,->
- taille de l’objet :sizeof
- relations d’ordre : <, <=, >,>=
- référence et déréférencement : &, *,[ ]
- séquençage :,
- regroupement de sous-expressions 🙁 )
- conversion de type 🙁typename)
C utilise l’opérateur =(utilisé en mathématiques pour exprimer l’égalité) pour indiquer l’affectation, suivant le précédent de Fortran et PL/I , mais contrairement à ALGOL et ses dérivés. C utilise l’opérateur ==pour tester l’égalité. La similitude entre ces deux opérateurs (affectation et égalité) peut entraîner l’utilisation accidentelle de l’un à la place de l’autre, et dans de nombreux cas, l’erreur ne produit pas de message d’erreur (bien que certains compilateurs produisent des avertissements). Par exemple, l’expression conditionnelle if (a == b + 1)peut être écrite par erreur sous la forme if (a = b + 1), qui sera évaluée comme vraie si an’est pas zéro après l’affectation. [28]
La priorité de l’ opérateur C n’est pas toujours intuitive. Par exemple, l’opérateur ==est plus étroitement lié que (est exécuté avant) les opérateurs &(ET au niveau du bit) et |(OU au niveau du bit) dans des expressions telles que x & 1 == 0, qui doivent être écrites comme (x & 1) == 0si c’était l’intention du codeur. [29]
Exemple “Hello, world”
“Bonjour le monde!” programme de Brian Kernighan (1978)
L’exemple ” hello, world “, qui figurait dans la première édition de K&R , est devenu le modèle d’un programme d’introduction dans la plupart des manuels de programmation. Le programme affiche “hello, world” sur la sortie standard , qui est généralement un terminal ou un écran.
La version originale était : [30]
principal () { printf ( “bonjour, monde n ” ); }
Un programme “hello, world” conforme à la norme est : [a]
#include <stdio.h> int principal ( vide ) { printf ( “bonjour, monde n ” ); }
La première ligne du programme contient une directive de prétraitement , indiquée par #include. Cela oblige le compilateur à remplacer cette ligne par le texte entier de l’ stdio.hen-tête standard, qui contient des déclarations pour les fonctions d’entrée et de sortie standard telles que printfet scanf. Les crochets angulaires entourant stdio.hindiquent que stdio.hest localisé à l’aide d’une stratégie de recherche qui préfère les en-têtes fournis avec le compilateur aux autres en-têtes portant le même nom, par opposition aux guillemets doubles qui incluent généralement des fichiers d’en-tête locaux ou spécifiques au projet.
La ligne suivante indique qu’une fonction nommée mainest en cours de définition. La mainfonction a un but particulier dans les programmes C ; l’environnement d’exécution appelle la mainfonction pour commencer l’exécution du programme. Le spécificateur de type intindique que la valeur renvoyée à l’invocateur (dans ce cas, l’environnement d’exécution) à la suite de l’évaluation de la mainfonction est un entier. Le mot-clé voiden tant que liste de paramètres indique que cette fonction ne prend aucun argument. [c]
L’accolade ouvrante indique le début de la définition de la mainfonction.
La ligne suivante appelle (détourne l’exécution vers) une fonction nommée printf, qui dans ce cas est fournie par une bibliothèque système . Dans cet appel, la printffonction reçoit ( fournie avec) un seul argument, l’adresse du premier caractère de la chaîne littérale “hello, worldn” . Le littéral de chaîne est un tableau sans nom avec des éléments de type char, configuré automatiquement par le compilateur avec un caractère final de valeur 0 pour marquer la fin du tableau ( printfdoit le savoir). Le nest une séquence d’échappement que C traduit en un caractère de saut de ligne , qui en sortie signifie la fin de la ligne actuelle. La valeur de retour duprintfLa fonction est de type int, mais elle est silencieusement ignorée car elle n’est pas utilisée. (Un programme plus prudent pourrait tester la valeur de retour pour déterminer si la printffonction a réussi ou non.) Le point-virgule ;termine l’instruction.
L’accolade fermante indique la fin du code de la mainfonction. Selon la spécification C99 et plus récente, la mainfonction, contrairement à toute autre fonction, renverra implicitement une valeur de 0lorsqu’elle atteint le }qui termine la fonction. (Auparavant, une return 0;instruction explicite était requise.) Ceci est interprété par le système d’exécution comme un code de sortie indiquant une exécution réussie. [31]
Types de données
Apprendre encore plus Cette section a besoin de citations supplémentaires pour vérification . ( octobre 2012 )Aidez -nous à améliorer cet article en ajoutant des citations à des sources fiables . Le matériel non sourcé peut être contesté et supprimé. (Découvrez comment et quand supprimer ce modèle de message) |
Le système de type en C est statique et faiblement typé , ce qui le rend similaire au système de type des descendants d’ ALGOL tels que Pascal . [32] Il existe des types intégrés pour les entiers de différentes tailles, à la fois signés et non signés, les nombres à virgule flottante et les types énumérés ( enum). Le type entier charest souvent utilisé pour les caractères à un octet. C99 a ajouté un type de données booléen . Il existe également des types dérivés, notamment des tableaux , des pointeurs , des enregistrements ( struct) et des unions ( union).
C est souvent utilisé dans la programmation de systèmes de bas niveau où des échappements du système de type peuvent être nécessaires. Le compilateur tente de garantir l’exactitude du type de la plupart des expressions, mais le programmeur peut remplacer les vérifications de différentes manières, soit en utilisant un transtypage de type pour convertir explicitement une valeur d’un type à un autre, soit en utilisant des pointeurs ou des unions pour réinterpréter les bits sous-jacents. d’un objet de données d’une autre manière.
Certains trouvent la syntaxe de déclaration de C peu intuitive, en particulier pour les pointeurs de fonction . (L’idée de Ritchie était de déclarer les identificateurs dans des contextes ressemblant à leur usage : ” la déclaration reflète l’usage “.) [33]
Les conversions arithmétiques habituelles de C permettent de générer un code efficace, mais peuvent parfois produire des résultats inattendus. Par exemple, une comparaison d’entiers signés et non signés de largeur égale nécessite une conversion de la valeur signée en non signée. Cela peut générer des résultats inattendus si la valeur signée est négative.
Pointeurs
C prend en charge l’utilisation de pointeurs , un type de référence qui enregistre l’adresse ou l’emplacement d’un objet ou d’une fonction en mémoire. Les pointeurs peuvent être déréférencés pour accéder aux données stockées à l’adresse pointée ou pour invoquer une fonction pointée. Les pointeurs peuvent être manipulés à l’aide de l’affectation ou de l’arithmétique des pointeurs . La représentation à l’exécution d’une valeur de pointeur est généralement une adresse mémoire brute (peut-être augmentée par un champ de décalage dans le mot), mais comme le type d’un pointeur inclut le type de l’objet pointé, les expressions comprenant des pointeurs peuvent être vérifiées. au moment de la compilation. L’arithmétique du pointeur est automatiquement mise à l’échelle par la taille du type de données pointé. Les pointeurs sont utilisés à de nombreuses fins en C. Chaînes de textesont généralement manipulés à l’aide de pointeurs dans des tableaux de caractères. L’allocation de mémoire dynamique est effectuée à l’aide de pointeurs. De nombreux types de données, tels que les arbres , sont généralement implémentés en tant qu’objets alloués dynamiquement structliés entre eux à l’aide de pointeurs. Les pointeurs vers des fonctions sont utiles pour transmettre des fonctions en tant qu’arguments à des fonctions d’ordre supérieur (telles que qsort ou bsearch ) ou en tant que rappels à invoquer par des gestionnaires d’événements. [31]
Une valeur de pointeur nulle ne pointe explicitement vers aucun emplacement valide. Le déréférencement d’une valeur de pointeur null n’est pas défini, ce qui entraîne souvent une erreur de segmentation . Les valeurs de pointeur nulles sont utiles pour indiquer des cas particuliers tels que l’absence de pointeur “suivant” dans le nœud final d’une liste chaînée ou comme indication d’erreur provenant de fonctions renvoyant des pointeurs. Dans des contextes appropriés dans le code source, comme pour l’affectation à une variable de pointeur, une constante de pointeur nulle peut être écrite sous la forme 0, avec ou sans transtypage explicite en un type de pointeur, ou comme la NULLmacro définie par plusieurs en-têtes standard. Dans les contextes conditionnels, les valeurs de pointeur null sont évaluées à false, tandis que toutes les autres valeurs de pointeur sont évaluées à true.
Les pointeurs vides ( void *) pointent vers des objets de type non spécifié, et peuvent donc être utilisés comme pointeurs de données “génériques”. Étant donné que la taille et le type de l’objet pointé ne sont pas connus, les pointeurs vides ne peuvent pas être déréférencés, et l’arithmétique de pointeur sur eux n’est pas autorisée, bien qu’ils puissent facilement être (et dans de nombreux contextes implicitement) convertis vers et à partir de n’importe quel autre pointeur d’objet taper. [31]
L’utilisation négligente des pointeurs est potentiellement dangereuse. Parce qu’elles ne sont généralement pas cochées, une variable de pointeur peut être amenée à pointer vers n’importe quel emplacement arbitraire, ce qui peut provoquer des effets indésirables. Bien que les pointeurs correctement utilisés pointent vers des endroits sûrs, ils peuvent être amenés à pointer vers des endroits dangereux en utilisant une arithmétique de pointeur invalide ; les objets vers lesquels ils pointent peuvent continuer à être utilisés après la désallocation ( pointeurs suspendus ) ; ils peuvent être utilisés sans avoir été initialisés ( pointeurs sauvages); ou ils peuvent se voir attribuer directement une valeur non sécurisée à l’aide d’un transtypage, d’une union ou via un autre pointeur corrompu. En général, C est permissif en permettant la manipulation et la conversion entre les types de pointeurs, bien que les compilateurs fournissent généralement des options pour différents niveaux de vérification. Certains autres langages de programmation résolvent ces problèmes en utilisant des types de référence plus restrictifs.
Tableaux
Les types de tableau en C sont traditionnellement d’une taille fixe et statique spécifiée au moment de la compilation. La norme C99, plus récente, autorise également une forme de tableaux de longueur variable. Cependant, il est également possible d’allouer un bloc de mémoire (de taille arbitraire) au moment de l’exécution, en utilisant la mallocfonction de la bibliothèque standard, et de le traiter comme un tableau.
Étant donné que les tableaux sont toujours accessibles (en fait) via des pointeurs, les accès aux tableaux ne sont généralement pas vérifiés par rapport à la taille du tableau sous-jacent, bien que certains compilateurs puissent fournir une vérification des limites en option. [34] [35] Les violations des limites du tableau sont donc possibles et peuvent entraîner diverses répercussions, notamment des accès illégaux à la mémoire, la corruption de données, des dépassements de mémoire tampon et des exceptions d’exécution.
C n’a pas de disposition spéciale pour déclarer des tableaux multidimensionnels , mais s’appuie plutôt sur la récursivité dans le système de type pour déclarer des tableaux de tableaux, ce qui accomplit effectivement la même chose. Les valeurs d’index du “tableau multidimensionnel” résultant peuvent être considérées comme augmentant dans l’ordre des lignes principales . Les tableaux multidimensionnels sont couramment utilisés dans les algorithmes numériques (principalement issus de l’algèbre linéaire appliquée) pour stocker des matrices. La structure du réseau C est bien adaptée à cette tâche particulière. Cependant, dans les premières versions de C, les limites du tableau doivent être des valeurs fixes connues ou bien transmises explicitement à tout sous-programme qui les nécessite, et les tableaux de tableaux dimensionnés dynamiquement ne sont pas accessibles à l’aide de la double indexation. (Une solution de contournement consistait à allouer au tableau un “vecteur de ligne” supplémentaire de pointeurs vers les colonnes.) C99 a introduit des “tableaux de longueur variable” qui résolvent ce problème.
L’exemple suivant utilisant le C moderne (C99 ou version ultérieure) montre l’allocation d’un tableau bidimensionnel sur le tas et l’utilisation de l’indexation de tableau multidimensionnel pour les accès (qui peut utiliser la vérification des limites sur de nombreux compilateurs C) :
int func ( int N , int M ) { float ( * p )[ N ][ M ] = malloc ( sizeof * p ); si ( ! p ) retour -1 ; pour ( int je = 0 ; je < N ; je ++ ) pour ( int j = 0 ; j < M ; j ++ ) ( * p )[ je ][ j ] = je + j ; print_array ( N , M , p ); libre ( p ); retour 1 ; }
Et voici une implémentation similaire utilisant la fonctionnalité Auto VLA de C99 :
int func ( int N , int M ) { // Attention : des vérifications doivent être effectuées pour s’assurer que N*M*sizeof(float) ne dépasse PAS les limites des VLA automatiques et respecte la taille de pile disponible. float p [ N ][ M ] ; // auto VLA est conservé sur la pile et dimensionné lorsque la fonction est invoquée pour ( int i = 0 ; i < N ; i ++ ) pour ( int j = 0 ; j < M ; j ++ ) p [ je ][ j ] = je + j ; // pas besoin de free(p) puisqu’il disparaîtra à la sortie de la fonction, avec le reste du frame de pile return 1 ; }
Interchangeabilité tableau-pointeur
La notation en indice x[i](où xdésigne un pointeur) est du sucre syntaxique pour *(x+i). [36] Profitant de la connaissance du compilateur du type de pointeur, l’adresse qui x + ipointe vers n’est pas l’adresse de base (pointée par x) incrémentée d’ ioctets, mais est plutôt définie comme étant l’adresse de base incrémentée de imultipliée par la taille d’un élément qui xpointe vers. Ainsi, x[i]désigne le i+1ème élément du tableau.
De plus, dans la plupart des contextes d’expression (une exception notable est l’opérande de sizeof), une expression de type tableau est automatiquement convertie en un pointeur vers le premier élément du tableau. Cela implique qu’un tableau n’est jamais copié dans son ensemble lorsqu’il est nommé en tant qu’argument d’une fonction, mais que seule l’adresse de son premier élément est transmise. Par conséquent, bien que les appels de fonction en C utilisent une sémantique de passage par valeur , les tableaux sont en fait passés par référence .
La taille totale d’un tableau xpeut être déterminée en l’appliquant sizeofà une expression de type tableau. La taille d’un élément peut être déterminée en appliquant l’opérateur sizeofà tout élément déréférencé d’un tableau A, comme dans n = sizeof A[0]. Ceci, le nombre d’éléments dans un tableau déclaré Apeut être déterminé comme sizeof A / sizeof A[0]. Notez que si seul un pointeur vers le premier élément est disponible comme c’est souvent le cas en code C à cause de la conversion automatique décrite ci-dessus, les informations sur le type complet du tableau et sa longueur sont perdues.
Gestion de la mémoire
L’une des fonctions les plus importantes d’un langage de programmation est de fournir des fonctionnalités de gestion de la mémoire et des objets stockés en mémoire. C fournit trois manières principales d’allouer de la mémoire aux objets : [31]
- Allocation de mémoire statique : l’espace pour l’objet est fourni dans le binaire au moment de la compilation ; ces objets ont une extension (ou durée de vie) tant que le binaire qui les contient est chargé en mémoire.
- Allocation automatique de mémoire : les objets temporaires peuvent être stockés sur la pile , et cet espace est automatiquement libéré et réutilisable après la sortie du bloc dans lequel ils sont déclarés.
- Allocation de mémoire dynamique : des blocs de mémoire de taille arbitraire peuvent être demandés au moment de l’exécution à l’aide de fonctions de bibliothèque telles qu’à mallocpartir d’une région de mémoire appelée le tas ; ces blocs persistent jusqu’à ce qu’ils soient ensuite libérés pour être réutilisés en appelant la fonction de bibliothèque reallocoufree
Ces trois approches sont appropriées dans différentes situations et ont divers compromis. Par exemple, l’allocation de mémoire statique a peu de temps système d’allocation, l’allocation automatique peut impliquer un peu plus de temps système et l’allocation de mémoire dynamique peut potentiellement avoir beaucoup de temps système pour l’allocation et la désallocation. La nature persistante des objets statiques est utile pour maintenir les informations d’état à travers les appels de fonction, l’allocation automatique est facile à utiliser mais l’espace de pile est généralement beaucoup plus limité et transitoire que la mémoire statique ou l’espace de tas, et l’allocation de mémoire dynamique permet une allocation pratique des objets dont La taille n’est connue qu’au moment de l’exécution. La plupart des programmes C utilisent largement les trois.
Dans la mesure du possible, l’allocation automatique ou statique est généralement la plus simple car le stockage est géré par le compilateur, libérant ainsi le programmeur de la corvée potentiellement sujette aux erreurs d’allocation et de libération manuelles du stockage. Cependant, de nombreuses structures de données peuvent changer de taille au moment de l’exécution, et puisque les allocations statiques (et les allocations automatiques avant C99) doivent avoir une taille fixe au moment de la compilation, il existe de nombreuses situations dans lesquelles une allocation dynamique est nécessaire. [31] Avant la norme C99, les tableaux de taille variable en étaient un exemple courant. (Voir l’article surmallocpour un exemple de tableaux alloués dynamiquement.) Contrairement à l’allocation automatique, qui peut échouer au moment de l’exécution avec des conséquences incontrôlées, les fonctions d’allocation dynamique renvoient une indication (sous la forme d’une valeur de pointeur nulle) lorsque le stockage requis ne peut pas être alloué. (Une allocation statique trop importante est généralement détectée par l’ éditeur de liens ou le chargeur , avant même que le programme ne puisse commencer son exécution.)
Sauf indication contraire, les objets statiques contiennent des valeurs de pointeur nulles ou nulles au démarrage du programme. Les objets alloués automatiquement et dynamiquement ne sont initialisés que si une valeur initiale est explicitement spécifiée ; sinon, ils ont initialement des valeurs indéterminées (généralement, quel que soit le modèle de bits présent dans le stockage , qui peut même ne pas représenter une valeur valide pour ce type). Si le programme tente d’accéder à une valeur non initialisée, les résultats sont indéfinis. De nombreux compilateurs modernes tentent de détecter et d’avertir de ce problème, mais des faux positifs et des faux négatifs peuvent se produire.
L’allocation de mémoire de tas doit être synchronisée avec son utilisation réelle dans n’importe quel programme pour être réutilisée autant que possible. Par exemple, si le seul pointeur vers une allocation de mémoire de tas sort de la portée ou a sa valeur écrasée avant d’être désallouée explicitement, alors cette mémoire ne peut pas être récupérée pour une réutilisation ultérieure et est essentiellement perdue pour le programme, un phénomène connu sous le nom de mémoire fuite . A l’inverse, il est possible que de la mémoire soit libérée, mais référencée par la suite, conduisant à des résultats imprévisibles. En règle générale, les symptômes d’échec apparaissent dans une partie du programme sans rapport avec le code à l’origine de l’erreur, ce qui rend difficile le diagnostic de l’échec. Ces problèmes sont améliorés dans les langages avec récupération automatique de la mémoire .
Bibliothèques
Le langage de programmation C utilise les bibliothèques comme principale méthode d’extension. En C, une bibliothèque est un ensemble de fonctions contenues dans un seul fichier “archive”. Chaque bibliothèque possède généralement un fichier d’en-tête , qui contient les prototypes des fonctions contenues dans la bibliothèque pouvant être utilisées par un programme, ainsi que des déclarations de types de données spéciaux et de symboles de macro utilisés avec ces fonctions. Pour qu’un programme utilise une bibliothèque, il doit inclure le fichier d’en-tête de la bibliothèque, et la bibliothèque doit être liée au programme, ce qui dans de nombreux cas nécessite des indicateurs de compilateur (par exemple, -lm, raccourci pour “lier la bibliothèque mathématique”). [31]
La bibliothèque C la plus courante est la bibliothèque standard C , qui est spécifiée par les normes ISO et ANSI C et est fournie avec chaque implémentation C (les implémentations qui ciblent des environnements limités tels que les systèmes embarqués peuvent ne fournir qu’un sous-ensemble de la bibliothèque standard). Cette bibliothèque prend en charge l’entrée et la sortie de flux, l’allocation de mémoire, les mathématiques, les chaînes de caractères et les valeurs temporelles. Plusieurs en-têtes standard distincts (par exemple, stdio.h) spécifient les interfaces pour ces fonctionnalités et d’autres fonctionnalités de bibliothèque standard.
Un autre ensemble commun de fonctions de la bibliothèque C sont celles utilisées par les applications spécifiquement ciblées pour les systèmes Unix et de type Unix , en particulier les fonctions qui fournissent une interface avec le noyau . Ces fonctions sont détaillées dans diverses normes telles que POSIX et la spécification UNIX unique .
Étant donné que de nombreux programmes ont été écrits en C, il existe une grande variété d’autres bibliothèques disponibles. Les bibliothèques sont souvent écrites en C car les compilateurs C génèrent un code objet efficace ; les programmeurs créent ensuite des interfaces avec la bibliothèque afin que les routines puissent être utilisées à partir de langages de niveau supérieur tels que Java , Perl et Python . [31]
Gestion des fichiers et flux
L’entrée et la sortie de fichier (E/S) ne font pas partie du langage C lui-même mais sont plutôt gérées par des bibliothèques (telles que la bibliothèque standard C) et leurs fichiers d’en-tête associés (par exemple stdio.h). La gestion des fichiers est généralement mise en œuvre via des E/S de haut niveau qui fonctionnent via des flux . Un flux est de ce point de vue un flux de données indépendant des appareils, tandis qu’un fichier est un appareil concret. Les E/S de haut niveau se font par l’association d’un flux à un fichier. Dans la bibliothèque standard C, un tampon (une zone mémoire ou une file d’attente) est temporairement utilisé pour stocker les données avant qu’elles ne soient envoyées à la destination finale. Cela réduit le temps passé à attendre des périphériques plus lents, par exemple un disque dur ou un disque SSD. Les fonctions d’E / S de bas niveau ne font pas partie de la bibliothèque C standard [ clarification nécessaire ] mais font généralement partie de la programmation “bare metal” (programmation indépendante de tout système d’exploitation , comme la plupart des programmations embarquées ). À quelques exceptions près, les implémentations incluent des E/S de bas niveau.
Outils de langage
Apprendre encore plus Cette section a besoin de citations supplémentaires pour vérification . ( juillet 2014 )Aidez -nous à améliorer cet article en ajoutant des citations à des sources fiables . Le matériel non sourcé peut être contesté et supprimé. (Découvrez comment et quand supprimer ce modèle de message) |
Un certain nombre d’outils ont été développés pour aider les programmeurs C à trouver et à corriger des instructions avec un comportement indéfini ou des expressions éventuellement erronées, avec une plus grande rigueur que celle fournie par le compilateur. L’outil peluche a été le premier de ce type, entraînant de nombreux autres.
La vérification et l’audit automatisés du code source sont bénéfiques dans n’importe quel langage, et pour C, de nombreux outils de ce type existent, tels que Lint . Une pratique courante consiste à utiliser Lint pour détecter le code douteux lors de la première écriture d’un programme. Une fois qu’un programme passe Lint, il est ensuite compilé à l’aide du compilateur C. De plus, de nombreux compilateurs peuvent éventuellement avertir des constructions syntaxiquement valides qui sont susceptibles d’être en fait des erreurs. MISRA C est un ensemble exclusif de directives pour éviter un tel code douteux, développé pour les systèmes embarqués. [37]
Il existe également des compilateurs, des bibliothèques et des mécanismes au niveau du système d’exploitation pour effectuer des actions qui ne font pas partie du standard C, telles que la vérification des limites pour les tableaux, la détection du dépassement de mémoire tampon , la sérialisation , le suivi dynamique de la mémoire et la récupération automatique des ordures .
Des outils tels que Purify ou Valgrind et la liaison avec des bibliothèques contenant des versions spéciales des fonctions d’allocation de mémoire peuvent aider à découvrir les erreurs d’exécution dans l’utilisation de la mémoire.
Les usages
Le langage de programmation C
C est largement utilisé pour la programmation de systèmes dans la mise en œuvre de systèmes d’exploitation et d’applications de systèmes embarqués . [38] Ceci pour plusieurs raisons :
- Le code généré après la compilation ne demande pas beaucoup de fonctionnalités système et peut être appelé à partir d’un code de démarrage de manière simple – il est simple à exécuter.
- Les instructions et les expressions du langage C correspondent généralement bien aux séquences d’instructions pour le processeur cible, et par conséquent, il y a une faible demande d’ exécution sur les ressources système – c’est rapide à exécuter.
- Le langage facilite la superposition de structures sur des blocs de données binaires, permettant aux données d’être comprises, naviguées et modifiées – il peut écrire des structures de données, même des systèmes de fichiers.
- Le langage prend en charge un riche ensemble d’opérateurs, y compris la manipulation de bits, pour l’arithmétique et la logique entières, et peut-être différentes tailles de nombres à virgule flottante – il peut traiter efficacement des données structurées de manière appropriée.
- Le matériel de la plate-forme est accessible avec des pointeurs et des punning de type , de sorte que les fonctionnalités spécifiques au système (par exemple , les registres de contrôle/état, les registres d’ E/S ) peuvent être configurées et utilisées avec du code écrit en C – il interagit bien avec la plate-forme sur laquelle il s’exécute.
- Selon l’éditeur de liens et l’environnement, le code C peut également appeler des bibliothèques écrites en langage d’assemblage et peut être appelé à partir du langage d’assemblage – il interagit bien avec d’autres codes.
- C a un écosystème très mature et large, comprenant des compilateurs, des débogueurs et des utilitaires open source, et est la norme de facto. Il est probable que les pilotes existent déjà en C, ou qu’il existe une architecture CPU similaire en tant que back-end d’un compilateur C, donc il y a moins d’incitation à choisir un autre langage.
Historiquement, C était parfois utilisé pour le développement Web en utilisant l’ interface de passerelle commune (CGI) comme “passerelle” pour les informations entre l’application Web, le serveur et le navigateur. [39] C peut avoir été choisi parmi les langages interprétés en raison de sa vitesse, de sa stabilité et de sa disponibilité quasi universelle. [40] Ce n’est plus une pratique courante pour le développement Web de se faire en C, [41] et de nombreux autres outils de développement Web existent.
Une conséquence de la grande disponibilité et de l’efficacité de C est que les compilateurs , les bibliothèques et les interpréteurs d’autres langages de programmation sont souvent implémentés en C. Par exemple, les implémentations de référence de Python , Perl , Ruby et PHP sont écrites en C.
C permet aux programmeurs de créer des implémentations efficaces d’algorithmes et de structures de données, car la couche d’abstraction du matériel est mince et sa surcharge est faible, un critère important pour les programmes à forte intensité de calcul. Par exemple, la bibliothèque d’arithmétique à précision multiple GNU , la bibliothèque scientifique GNU , Mathematica et MATLAB sont entièrement ou partiellement écrites en C. De nombreux langages prennent en charge l’appel de fonctions de bibliothèque en C, par exemple, le framework basé sur Python NumPy utilise C pour la haute -aspects de performance et d’interaction avec le matériel.
C est parfois utilisé comme langage intermédiaire par des implémentations d’autres langages. Cette approche peut être utilisée pour la portabilité ou la commodité ; en utilisant C comme langage intermédiaire, des générateurs de code supplémentaires spécifiques à la machine ne sont pas nécessaires. C a certaines fonctionnalités, telles que les directives de préprocesseur de numéro de ligne et les virgules superflues facultatives à la fin des listes d’initialisation, qui prennent en charge la compilation du code généré. Cependant, certaines des lacunes de C ont incité le développement d’autres langages basés sur C spécifiquement conçus pour être utilisés comme langages intermédiaires, tels que C– .
C a également été largement utilisé pour implémenter des applications utilisateur final . [ citation nécessaire ] Cependant, de telles applications peuvent également être écrites dans des langages plus récents et de niveau supérieur.
Limites
la puissance du langage d’assemblage et la commodité de … langage d’assemblage
— Dennis Ritchie, [42]
Alors que C a été populaire, influent et a connu un énorme succès, il présente des inconvénients, notamment :
- La gestion standard de la mémoire dynamique avec mallocet freeest sujette aux erreurs. Les bogues incluent : Fuites de mémoire lorsque la mémoire est allouée mais pas libérée ; et l’accès à la mémoire précédemment libérée.
- L’utilisation de pointeurs et la manipulation directe de la mémoire signifient que la corruption de la mémoire est possible, peut-être en raison d’une erreur du programmeur ou d’une vérification insuffisante des mauvaises données.
- Étant donné que le code généré par le compilateur contient lui-même peu de vérifications, il incombe au programmeur de considérer tous les résultats possibles et de se protéger contre les dépassements de mémoire tampon, la vérification des limites du tableau, les débordements de pile, l’épuisement de la mémoire, les conditions de concurrence, l’isolation des threads, etc.
- L’utilisation de pointeurs et la manipulation de ces derniers à l’exécution signifie qu’il peut y avoir deux façons d’accéder aux mêmes données (crénelage), ce qui n’est pas déterminable au moment de la compilation. Cela signifie que certaines optimisations qui peuvent être disponibles pour d’autres langages ne sont pas possibles en C. Fortran est considéré comme plus rapide.
- Certaines des fonctions standard de la bibliothèque, par exemple scanf, peuvent entraîner des dépassements de mémoire tampon.
- Il existe une standardisation limitée dans la prise en charge des variantes de bas niveau dans le code généré, par exemple : différentes conventions d’appel de fonction ; différentes conventions d’emballage de structure ; ordre différent des octets dans des entiers plus grands (y compris l’endianité). Dans de nombreuses implémentations de langage, certaines de ces options peuvent être gérées avec la directive du préprocesseur #pragma, [43] et d’autres avec des mots clés supplémentaires, par exemple utiliser __cdeclla convention d’appel. Mais la directive et les options ne sont pas systématiquement prises en charge. [44]
- Le langage ne prend pas directement en charge l’orientation objet, l’introspection, l’évaluation d’expressions à l’exécution, les génériques, les exceptions.
- Il existe peu de garde-fous contre l’utilisation inappropriée des fonctionnalités du langage, ce qui peut conduire à un code non maintenable.
À certaines fins, des styles restreints de C ont été adoptés, par exemple MISRA C , dans le but de réduire les risques de bogues. Il existe des outils qui peuvent atténuer certains de ces inconvénients. Certains de ces inconvénients ont incité la construction d’autres langues.
Langues associées
Le graphique de l’indice TIOBE , montrant une comparaison de la popularité de divers langages de programmation [45]
C a influencé directement et indirectement de nombreux langages ultérieurs tels que C # , D , Go , Java , JavaScript , Limbo , LPC , Perl , PHP , Python et le C shell d’Unix . [46] L’influence la plus envahissante a été syntaxique; tous les langages mentionnés combinent la syntaxe d’ instruction et d’expression (plus ou moins reconnaissable) du C avec des systèmes de types, des modèles de données et/ou des structures de programme à grande échelle qui diffèrent de ceux du C, parfois radicalement.
Plusieurs interpréteurs C ou quasi-C existent, dont Ch et CINT , qui peuvent également être utilisés pour les scripts.
Lorsque les langages de programmation orientés objet sont devenus populaires, C++ et Objective-C étaient deux extensions différentes de C qui fournissaient des capacités orientées objet. Les deux langages ont été implémentés à l’origine en tant que compilateurs source à source ; le code source a été traduit en C, puis compilé avec un compilateur C. [47]
Le langage de programmation C++ (initialement nommé “C avec classes “) a été conçu par Bjarne Stroustrup comme une approche pour fournir des fonctionnalités orientées objet avec une syntaxe de type C. [48] C++ ajoute une plus grande force de frappe, une portée et d’autres outils utiles dans la programmation orientée objet, et permet une programmation générique via des modèles. Presque un sur-ensemble de C, C++ prend désormais en charge la plupart de C, à quelques exceptions près .
Objective-C était à l’origine une couche très “mince” au-dessus de C, et reste un sur- ensemble strict de C qui permet la programmation orientée objet en utilisant un paradigme de typage hybride dynamique/statique. Objective-C tire sa syntaxe à la fois de C et de Smalltalk : la syntaxe qui implique le prétraitement, les expressions, les déclarations de fonctions et les appels de fonctions est héritée de C, tandis que la syntaxe des fonctionnalités orientées objet était à l’origine tirée de Smalltalk.
En plus de C++ et Objective-C , Ch , Cilk et Unified Parallel C sont presque des sur-ensembles de C.
Voir également
- Portail de programmation informatique
- Portail de logiciels gratuits et open source
- Compatibilité de C et C++
- Comparaison de Pascal et C
- Comparaison des langages de programmation
- Concours international de code C obscurci
- Liste des langages de programmation basés sur C
- Liste des compilateurs C
Remarques
- ^ L’exemple de code original se compilera sur la plupart des compilateurs modernes qui ne sont pas en mode de conformité standard strict, mais il n’est pas entièrement conforme aux exigences de C89 ou C99. En effet, C99 nécessite la production d’un message de diagnostic.
- ^ Lamainfonction a en fait deux arguments,int argcetchar *argv[], respectivement, qui peuvent être utilisés pour gérer les arguments de la ligne de commande . La norme ISO C (section 5.1.2.2.1) exige que les deux formes demainsoient prises en charge, ce qui est un traitement spécial qui n’est accordé à aucune autre fonction.
Références
- ^ un b Kernighan, Brian W. ; Ritchie, Dennis M. (février 1978). Le langage de programmation C (1ère éd.). Englewood Cliffs, New Jersey : Prentice Hall . ISBN 978-0-13-110163-0.
- ^ Ritchie (1993) : “Thompson avait fait une brève tentative pour produire un système codé dans une première version de C – avant les structures – en 1972, mais avait abandonné l’effort.”
- ^ Fruderica (13 décembre 2020). “Histoire de C” . Le cppreference.com . Archivé de l’original le 24 octobre 2020 . Consulté le 24 octobre 2020 .
- ^ Ritchie (1993) : “Le schéma de composition de type adopté par C doit une dette considérable à Algol 68, bien qu’il n’ait peut-être pas émergé sous une forme que les adhérents d’Algol approuveraient.”
- ^ un b “Verilog HDL (et C)” (PDF) . L’École de recherche en informatique de l’Université nationale australienne. 3 juin 2010. Archivé de l’original (PDF) le 6 novembre 2013 . Consulté le 19 août 2013 . années 1980 : ; Verilog a été introduit pour la première fois ; Verilog inspiré du langage de programmation C
- ^ un bcdef Ritchie ( 1993 ) _
- ^ ” Popularité du langage de programmation ” . 2009. Archivé de l’original le 16 janvier 2009 . Récupéré le 16 janvier 2009 .
- ^ “Index de communauté de programmation TIOBE” . 2009. Archivé de l’original le 4 mai 2009 . Consulté le 6 mai 2009 .
- ^ un b “l’Histoire de C” . fr.cppreference.com . Archivé de l’original le 29 mai 2018 . Consulté le 28 mai 2018 .
- ^ “Index TIOBE pour octobre 2021” . Consulté le 7 octobre 2021 .
- ^ Ritchie, Denis. “BCPL vers B vers C” . Archivé de l’original le 12 décembre 2019 . Consulté le 10 septembre 2019 .
- ^ un bcde Jensen , Richard (9 décembre 2020) . ” “Une sacrée chose stupide à faire” – les origines de C” . Ars Technica . Récupéré le 28 mars 2022 .
- ^ un b Johnson, SC ; Ritchie, DM (1978). “Portabilité des programmes C et du système UNIX”. Technicien du système Bell. J. _ 57 (6) : 2021-2048. CiteSeerX 10.1.1.138.35 . doi : 10.1002/j.1538-7305.1978.tb02141.x . S2CID 17510065 . (Remarque : le fichier PDF est une analyse OCR de l’original et contient un rendu de “IBM 370” en tant que “IBM 310”.)
- ^ McIlroy, MD (1987). Un lecteur Research Unix: extraits annotés du manuel du programmeur, 1971–1986 (PDF) (rapport technique) . CSTR. Bell Labs. p. 10. 139. Archivé (PDF) de l’original le 11 novembre 2017 . Consulté le 1er février 2015 .
- ^ “Pages de manuel C” . Manuel d’informations diverses sur FreeBSD (édition FreeBSD 13.0). 30 mai 2011. Archivé de l’original le 21 janvier 2021 . Consulté le 15 janvier 2021 . [1] Archivé le 21 janvier 2021 sur la Wayback Machine
- ^ Kernighan, Brian W. ; Ritchie, Dennis M. (mars 1988). Le langage de programmation C (2e éd.). Englewood Cliffs, New Jersey : Prentice Hall . ISBN 978-0-13-110362-7.
- ^ Stroustrup, Bjarne (2002). Rivalité fraternelle : C et C++ (PDF) (Rapport). Laboratoires AT&T. Archivé (PDF) de l’original le 24 août 2014 . Consulté le 14 avril 2014 .
- ^ C Intégrité . Organisation internationale de normalisation. 30 mars 1995. Archivé de l’original le 25 juillet 2018 . Consulté le 24 juillet 2018 .
- ^ “JTC1/SC22/WG14 – C” . Page d’accueil . ISO/CEI. Archivé de l’original le 12 février 2018 . Consulté le 2 juin 2011 .
- ^ Andrew Binstock (12 octobre 2011). “Entretien avec Herb Sutter” . Dr Dobbs . Archivé de l’original le 2 août 2013 . Consulté le 7 septembre 2013 .
- ^ “Calendrier C23 révisé WG 14 N 2759” (PDF) . www.open-std.org . Archivé (PDF) de l’original le 24 juin 2021 . Récupéré le 10 octobre 2021 .
- ^ “TR 18037 : C intégré” (PDF) . ISO/CEI. Archivé (PDF) de l’original le 25 février 2021 . Consulté le 26 juillet 2011 .
- ^ Harbison, Samuel P.; Steele, Guy L. (2002). C: Un manuel de référence (5e éd.). Englewood Cliffs, New Jersey : Prentice Hall . ISBN 978-0-13-089592-9.Contient une grammaire BNF pour C.
- ^ Kernighan & Ritchie (1996) , p. 192.
- ^ Kernighan & Ritchie (1978) , p. 3.
- ^ “Ébauche du comité ISO / CEI 9899: 201x (ISO C11)” (PDF) . Archivé (PDF) de l’original le 22 décembre 2017 . Consulté le 16 septembre 2011 .
- ^ Kernighan & Ritchie (1996) , pp. 192, 259.
- ^ “10 erreurs de programmation courantes en C++” . Cs.ucr.edu. Archivé de l’original le 21 octobre 2008 . Consulté le 26 juin 2009 .
- ^ Schultz, Thomas (2004). C et le 8051 (3e éd.). Otsego, MI : PageFree Publishing Inc. p. 20. ISBN 978-1-58961-237-2. Archivé de l’original le 29 juillet 2020 . Consulté le 10 février 2012 .
- ^ Kernighan & Ritchie (1978) , p. 6.
- ^ un bcdefg Klemens , Ben ( 2013 ) . 21e siècle C. O’Reilly Media . ISBN 978-1-4493-2714-9.
- ^ Feuer, Alan R.; Gehani, Narain H. (mars 1982). “Comparaison des langages de programmation C et Pascal”. Enquêtes informatiques ACM . 14 (1): 73–92. doi : 10.1145/356869.356872 . S2CID 3136859 .
- ^ Kernighan & Ritchie (1996) , p. 122.
- ^ Par exemple, gcc fournit _FORTIFY_SOURCE. “Fonctionnalités de sécurité : vérifications du tampon de temps de compilation (FORTIFY_SOURCE)” . fedoraproject.org. Archivé de l’original le 7 janvier 2007 . Consulté le 5 août 2012 .
- ^ เอี่ยมสิริวงศ์, โอภาศ (2016). Programmation avec C. Bangkok, Thaïlande : SE-EDUCATION PUBLIC COMPANY LIMITED. p. 225–230. ISBN 978-616-08-2740-4.
- ^ Raymond, Eric S. (11 octobre 1996). Le dictionnaire du nouveau pirate informatique (3e éd.). Presse du MIT. p. 432. ISBN 978-0-262-68092-9. Archivé de l’original le 12 novembre 2012 . Consulté le 5 août 2012 .
- ^ “Man Page for lint (freebsd Section 1)” . unix.com . 24 mai 2001 . Consulté le 15 juillet 2014 .
- ^ Dale, Nell B.; Weems, Puce (2014). Programmation et résolution de problèmes avec C++ (6e éd.). Burlington, MA : Apprentissage Jones et Bartlett. ISBN 978-1449694289. OCLC 894992484 .
- ^ Le livre source du Dr Dobb . États-Unis : Miller Freeman, Inc. Novembre-décembre 1995.
- ^ “Utiliser C pour la programmation CGI” . linuxjournal.com. 1er mars 2005. Archivé de l’original le 13 février 2010 . Consulté le 4 janvier 2010 .
- ^ Perkins, Luc (17 septembre 2013). “Développement Web en C : fou ? Ou fou comme un renard ?” . Moyen .
- ↑ Metz, Cade. “Dennis Ritchie : les épaules sur lesquelles Steve Jobs s’est tenu” . Câblé . Consulté le 19 avril 2022 .
- ^ “Directive #pragma en C/C++” . GeekspourGeeks . 11 septembre 2018 . Consulté le 10 avril 2022 .
- ^ “Pragmas” . Intel . Consulté le 10 avril 2022 .
- ^ McMillan, Robert (1er août 2013). “Est-ce que Java perd son Mojo?” . Câblé . Archivé de l’original le 15 février 2017 . Consulté le 5 mars 2017 .
- ^ O’Regan, Gérard (24 septembre 2015). Piliers de l’informatique : un recueil d’entreprises technologiques sélectionnées et essentielles . ISBN 978-3319214641. OCLC 922324121 .
- ^ Rauchwerger, Lawrence (2004). Langages et compilateurs pour le calcul parallèle : 16ème atelier international, LCPC 2003, College Station, TX, USA, 2-4 octobre 2003 : papiers révisés . Springer. ISBN 978-3540246442. OCLC 57965544 .
- ^ Stroustrup, Bjarne (1993). “Une histoire de C ++: 1979−1991” (PDF) . Archivé (PDF) de l’original le 2 février 2019 . Consulté le 9 juin 2011 .
Sources
- Ritchie, Dennis M. (mars 1993). “Le développement du langage C”. Avis ACM SIGPLAN . ACM. 28 (3): 201–208. doi : 10.1145/155360.155580 .
- Avec l’aimable autorisation de l’auteur, également chez Ritchie, Dennis M. “Chistory” . www.bell-labs.com . Consulté le 29 mars 2022 .
- En ligneRitchie, Dennis M. (1993). “Le développement du langage C” . La deuxième conférence ACM SIGPLAN sur l’histoire des langages de programmation (HOPL-II) . ACM . p. 201–208. doi : 10.1145/154766.155580 . ISBN 0-89791-570-4. Consulté le 4 novembre 2014 .
- Kernighan, Brian W. ; En ligneRitchie, Dennis M. (1996). Le langage de programmation C (2e éd.). Salle des apprentis . ISBN 7-302-02412-X.
Lectures complémentaires
- Kernighan, Brian ; Ritchie, Dennis (1988). Le langage de programmation C (2 éd.). Prentice Hall. ISBN 978-0131103627. (archive)
- Plauger, PJ (1992). La bibliothèque C standard (1 éd.). Prentice Hall. ISBN 978-0131315099. (la source)
- Banahan, M.; Brady, D.; Doran, M. (1991). Le livre C: avec la norme ANSI C (2 éd.). Addison-Wesley. ISBN 978-0201544336. (libre)
- Harbison, Samuel; Steele Jr, Guy (2002). C: Un manuel de référence (5 éd.). Person. ISBN 978-0130895929. (archive)
- Roi, KN (2008). Programmation C: Une approche moderne (2 éd.). WWNorton. ISBN 978-0393979503. (archive)
- Griffiths, David; Griffiths, Aube (2012). Tête première C (1 éd.). O’Reilly. ISBN 978-1449399917.
- Perry, Greg ; Miller, doyen (2013). Programmation C: Guide du débutant absolu (3 éd.). Qué. ISBN 978-0789751980.
- Deitel, Paul; Deitel, Harvey (2015). C: Comment programmer (8 éd.). Person. ISBN 978-0133976892.
- Gustedt, Jens (2019). Moderne C (2 éd.). Manning. ISBN 978-1617295812. (libre)
Liens externes
C (langage de programmation)dans les projets frères de Wikipédia
- Médias de Commons
- Nouvelles de Wikinews
- Citations de Wikiquote
- Manuels de Wikibooks
- Ressources de Wikiversité
- Site officiel du groupe de travail ISO C
- ISO/IEC 9899 , documents C officiels accessibles au public, y compris la justification C99
- “C99 avec corrigenda techniques TC1, TC2 et TC3 inclus” (PDF) . (3,61 Mo)
- Comp.lang.c Foire aux questions
- Une histoire de C , par Dennis Ritchie