How to Actually Learn C (2027 Edition)
Cette vidéo propose un guide pratique pour réécrire la commande ls en C, en implémentant les fonctionnalités de base (ls, ls -a, ls -l) tout en expliquant les concepts fondamentaux du langage C et les appels système Linux.

SYNTHÈSE STRUCTURÉE
Structure de base d’un programme C
Le présentateur commence par créer un programme minimal : int main(void) { return 0; }. Il explique que main retourne un entier, et que 0 signifie succès par convention. La compilation se fait avec gcc -Wall -Wextra -o lsbtw ls.c, les flags -Wall et -Wextra activant les avertissements du compilateur pour détecter les erreurs potentielles. Il insiste : « Ces deux flags de warning font que le compilateur nous dit quand on fait quelque chose de stupide. »
Gestion des arguments avec argc et argv
Pour que le programme accepte des arguments, la signature de main devient int main(int argc, char *argv[]). argc compte le nombre de mots tapés par l’utilisateur, et argv est un tableau de chaînes. Le présentateur montre comment gérer le cas où aucun argument n’est fourni : si argc > 1, le chemin est argv[1], sinon il utilise "." (le répertoire courant). Il souligne que argv[0] est toujours le nom du programme.
Ouverture d’un répertoire avec opendir
Pour lister un répertoire, il faut utiliser opendir() de <dirent.h>. Cette fonction retourne un pointeur de type DIR *, décrit comme « un ticket de vestiaire de l’OS » : on n’a pas besoin de connaître son contenu interne. Le code vérifie si opendir a échoué avec if (!dir) { perror("opendir"); return 1; }. La fonction perror() lit la variable globale errno et affiche un message d’erreur lisible.
Lecture des entrées avec readdir
La fonction readdir() retourne une structure struct dirent * contenant le champ d_name (le nom du fichier). On l’appelle en boucle jusqu’à ce qu’elle retourne NULL :
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
printf("%s\n", entry->d_name);
}
Le présentateur note que la flèche -> est un raccourci pour déréférencer un pointeur et accéder à un champ : « C’est tellement fréquent en C qu’ils ont inventé cette notation pour qu’on arrête de taper les parenthèses. »
Filtrage des fichiers cachés
Par défaut, ls n’affiche pas les fichiers commençant par un point. Le code ajoute donc une condition dans la boucle :
if (entry->d_name[0] == '.')
continue;
Cela saute les entrées dont le premier caractère est un point.
Fermeture du répertoire
Pour éviter une fuite de descripteurs de fichiers, il faut appeler closedir(dir) après la boucle. Le présentateur prévient : « Si on oublie de le faire, le programme va fuir des descripteurs de fichiers. C’est une petite fuite, mais une mauvaise habitude. »
Parsing des options avec getopt
Pour supporter les flags comme -a et -l, le présentateur utilise getopt() de <unistd.h>. Cette fonction parse les arguments en boucle et retourne le caractère de l’option trouvée. Un switch case gère chaque option :
while ((opt = getopt(argc, argv, "al")) != -1) {
switch (opt) {
case 'a':
show_all = 1;
break;
case 'l':
long_format = 1;
break;
default:
fprintf(stderr, "Usage: %s [-a] [-l] [path]\n", argv[0]);
return 1;
}
}
La variable globale optind donne l’index du premier argument non-option, ce qui remplace la vérification manuelle de argc.
Implémentation de ls -l avec stat
Le flag -l nécessite d’afficher les permissions, le nombre de liens, le propriétaire, le groupe, la taille, la date et le nom. Tout cela provient de l’appel système stat() (ou lstat() pour les liens symboliques). Le présentateur crée une fonction print_long() qui :
- Construit le chemin complet avec
snprintf()(pour éviter les débordements de buffer). - Appelle
lstat()pour remplir une structurestruct stat. - Convertit le champ
st_modeen chaîne de permissions via une fonctionmode_string()utilisant des macros commeS_ISDIR(),S_IRUSR, etc. - Récupère le nom d’utilisateur avec
getpwuid(st.st_uid)et le groupe avecgetgrgid(st.st_gid), avec un fallback sur"?"si la recherche échoue. - Formate la date avec
strftime()après avoir convertist_mtim.tv_secvialocaltime().
Gestion des erreurs avec perror
Chaque appel système (opendir, lstat) est suivi d’une vérification d’erreur. En cas d’échec, perror() affiche un message explicite et le programme retourne un code non nul. Par exemple, si on tape ./lsbtw /inexistant, le programme affiche opendir: No such file or directory.
CONCEPTS CLÉS
DIR *: Type opaque représentant un flux de répertoire, manipulé uniquement viaopendir,readdir,closedir.struct dirent: Structure contenant les informations d’une entrée de répertoire, notammentd_name.struct stat: Structure remplie parstat()oulstat(), contenant les métadonnées d’un fichier (type, permissions, taille, timestamps, etc.).getopt(): Fonction standard pour parser les options en ligne de commande, évitant d’écrire un parseur manuel.perror(): Fonction qui affiche un message d’erreur système basé sur la variableerrno.lstat()vsstat():lstat()ne suit pas les liens symboliques, contrairement àstat(). Pourls -l, on utiliselstat()pour afficher les informations du lien lui-même.
CONCLUSION
Cette vidéo montre qu’implémenter une commande système comme ls en C est accessible, même pour un débutant, à condition de maîtriser les appels système fondamentaux (opendir, readdir, stat) et les fonctions de la bibliothèque standard (getopt, perror, strftime). Le présentateur insiste sur l’importance de lire les pages de manuel (« C’est la page la plus importante de toute la vidéo ») et de gérer correctement les erreurs et les fuites de ressources. Le message principal est que la réécriture d’outils classiques en C (ou en Rust) n’est pas un exercice vain : elle permet de comprendre en profondeur le fonctionnement du système et d’améliorer ses compétences en programmation système.