Quels sont les concepts / techniques / fonctionnalités de langage que tout programmeur C décent devrait connaître / être au courant (exclure l'ingénierie logicielle générale et similaire et se concentrer uniquement sur des choses spécifiques C). Je voudrais savoir pour pouvoir combler certaines lacunes possibles dans mes connaissances en C.
Commencez par les questions C de Stack Overflow et voyez s'il y a quelque chose que vous ne savez pas.
chrisaycock
3
Le programmeur AC devrait probablement savoir que2 + 2 = 4
Edward Strange
21
Ils devraient connaître un magasin qui vend des chaussures pare-balles.
Adam Crossland
1
Il existe des centaines de livres écrits sur ce sujet. Votre question est vraiment assez vague. Vous devrez être plus précis pour obtenir des réponses décentes qui ne sont pas seulement une liste de choses. Et vu les réponses dégagées si loin de cette question, je pense qu'elle doit être retravaillée ou fermée.
Walter
2
Un autre langage de programmation?
Muhammad Alkarouri
Réponses:
19
Spécifique à C? Mis à part les constructions standard communes à la plupart des langages procéduraux, je dois dire:
(ab) utilisation du préprocesseur
éditeur de liens vs compilateur
Pointers Pointers Pointers!
Comment les tableaux sont des pointeurs sont des tableaux
Comment fonctionnent les chaînes C et comment elles sont également des pointeurs et des tableaux
Comment une mauvaise utilisation de la chaîne C peut entraîner des débordements de tampon
Comment lancer n'importe quoi sur quoi que ce soit (ce ne sont que des 1 et des 0 après tout :))
Gestion de mémoire manuelle malloc / gratuit
Stack vs Heap
Aliasing de pointeur, (pourquoi son illégal en C99)
Penser le développement en termes de modules (fichiers .h / .c) avec un ensemble de fonctions exposées publiquement au lieu de classes strictement
Le programmeur AC devrait connaître ... d'autres langues! ;-) Il est toujours utile de connaître les concepts d'autres langages de différents paradigmes, comme la POO, la programmation fonctionnelle, etc.
Plus sérieusement, un coup d'œil au concours de programmation obscurci est amusant et, curieusement, une bonne expérience aussi.
J'ai mentionné "débordements de tampon" dans un commentaire à la réponse de Pythagras, je devrais probablement clarifier ce que je voulais dire un peu. En C, il ne suffit pas de savoir que travailler directement avec la mémoire est dangereux - vous devez également comprendre les façons précises dont il est dangereux. Je n'aime pas vraiment la métaphore "se tirer dans le pied" pour tous ces cas - la plupart du temps, ce n'est pas vous qui appuyez sur la gâchette, mais souvent c'est un acteur avec des intérêts contraires au vôtre et / ou à vos utilisateurs '' .
Par exemple, dans une architecture avec une pile décroissante (les architectures les plus courantes correspondent à cette facture - x86 et ARM généralement inclus), lorsque vous appelez une fonction, l'adresse de retour de la fonction sera placée sur la pile après les variables locales définies dans le corps de la fonction. Donc, si vous déclarez un tampon en tant que variable locale et exposez cette variable au monde extérieur sans vérifier le dépassement de tampon, comme ceci:
void myFn(void){char buf[256];
gets(buf);}
un utilisateur externe peut vous envoyer une chaîne qui écrase l'adresse de retour de la pile - en gros, il peut changer l'idée d'exécution de votre programme du call-graph qui mène à la fonction actuelle. Ainsi, l'utilisateur vous donne une chaîne qui est la représentation binaire d'un code exécutable pour votre architecture, suffisamment de remplissage pour déborder la pile myFnet quelques données supplémentaires pour écraser l'adresse de retour pour myFnpointer vers le code qu'il vous a donné. Si cela se produit, alors quand myFnaurait normalement retourné le contrôle à son appelant, il se connectera au code fourni par l'utilisateur malveillant. Si vous écrivez du code C (ou C ++) susceptible d'être exposé à des utilisateurs non fiables, vous devez comprendre ce vecteur d'attaque. Vous devez comprendre pourquoi un débordement de tampon contre la pile est souvent (mais pas toujours) plus facilement exploitable qu'un autre contre le tas, et vous devez comprendre comment la mémoire du tas est disposée (pas trop en détail, nécessairement, mais le L'idée qu'une malloc()région a des structures de contrôle qui l'entourent peut aider à comprendre pourquoi votre programme se bloque dans une autre malloc(), ou dans free()).
C vous expose à des détails de bas niveau sur le fonctionnement de votre machine, et il vous donne un contrôle plus direct sur votre machine que tout autre langage édité par l'utilisateur largement utilisé aujourd'hui. Une grande puissance s'accompagne d'une grande responsabilité - vous devez réellement comprendre ces détails de bas niveau afin de travailler avec C de manière sûre et efficace.
2 + 2 = 4
Réponses:
Spécifique à C? Mis à part les constructions standard communes à la plupart des langages procéduraux, je dois dire:
la source
Comprenez les pointeurs et vous comprendrez les ordinateurs.
la source
En plus de l'excellente réponse de pythagras,
comment écrire (ou au moins lire) des déclarations compliquées, telles que
char (*(*funcs[4])())[10]
funcs est un tableau [4] de pointeurs sur une fonction renvoyant un pointeur sur le tableau [10] de char
la source
la source
Le programmeur AC devrait connaître ... d'autres langues! ;-) Il est toujours utile de connaître les concepts d'autres langages de différents paradigmes, comme la POO, la programmation fonctionnelle, etc.
Plus sérieusement, un coup d'œil au concours de programmation obscurci est amusant et, curieusement, une bonne expérience aussi.
la source
J'ai mentionné "débordements de tampon" dans un commentaire à la réponse de Pythagras, je devrais probablement clarifier ce que je voulais dire un peu. En C, il ne suffit pas de savoir que travailler directement avec la mémoire est dangereux - vous devez également comprendre les façons précises dont il est dangereux. Je n'aime pas vraiment la métaphore "se tirer dans le pied" pour tous ces cas - la plupart du temps, ce n'est pas vous qui appuyez sur la gâchette, mais souvent c'est un acteur avec des intérêts contraires au vôtre et / ou à vos utilisateurs '' .
Par exemple, dans une architecture avec une pile décroissante (les architectures les plus courantes correspondent à cette facture - x86 et ARM généralement inclus), lorsque vous appelez une fonction, l'adresse de retour de la fonction sera placée sur la pile après les variables locales définies dans le corps de la fonction. Donc, si vous déclarez un tampon en tant que variable locale et exposez cette variable au monde extérieur sans vérifier le dépassement de tampon, comme ceci:
un utilisateur externe peut vous envoyer une chaîne qui écrase l'adresse de retour de la pile - en gros, il peut changer l'idée d'exécution de votre programme du call-graph qui mène à la fonction actuelle. Ainsi, l'utilisateur vous donne une chaîne qui est la représentation binaire d'un code exécutable pour votre architecture, suffisamment de remplissage pour déborder la pile
myFn
et quelques données supplémentaires pour écraser l'adresse de retour pourmyFn
pointer vers le code qu'il vous a donné. Si cela se produit, alors quandmyFn
aurait normalement retourné le contrôle à son appelant, il se connectera au code fourni par l'utilisateur malveillant. Si vous écrivez du code C (ou C ++) susceptible d'être exposé à des utilisateurs non fiables, vous devez comprendre ce vecteur d'attaque. Vous devez comprendre pourquoi un débordement de tampon contre la pile est souvent (mais pas toujours) plus facilement exploitable qu'un autre contre le tas, et vous devez comprendre comment la mémoire du tas est disposée (pas trop en détail, nécessairement, mais le L'idée qu'unemalloc()
région a des structures de contrôle qui l'entourent peut aider à comprendre pourquoi votre programme se bloque dans une autremalloc()
, ou dansfree()
).C vous expose à des détails de bas niveau sur le fonctionnement de votre machine, et il vous donne un contrôle plus direct sur votre machine que tout autre langage édité par l'utilisateur largement utilisé aujourd'hui. Une grande puissance s'accompagne d'une grande responsabilité - vous devez réellement comprendre ces détails de bas niveau afin de travailler avec C de manière sûre et efficace.
la source
En plus des autres bonnes réponses, je voudrais ajouter des techniques de programmation défensive à la liste.
Par exemple, utiliser des assertions au début / à la fin des fonctions pour vérifier le contrat.
la source