Que se passera-t-il si je n’inclus pas les fichiers d’en-tête

Que se passera-t-il si je n’inclus pas les fichiers d’entête lors de l’exécution du programme ac? Je sais que je reçois des avertissements, mais le programme fonctionne parfaitement.

Je sais que les fichiers d’en-tête contiennent des déclarations de fonction. Par conséquent, lorsque je ne les inclut pas, comment le compilateur le comprend-il? Est-ce qu’il vérifie tous les fichiers d’en-tête?

Je sais que je reçois des avertissements, mais le programme fonctionne parfaitement.

C’est un inheritance regrettable du C pré-ANSI: le langage n’exigeait pas de prototypes de fonctions, le C standard le permet à ce jour (un avertissement peut généralement être émis pour trouver des fonctions appelées sans prototype).

Lorsque vous appelez une fonction sans prototype, le compilateur C émet des hypothèses sur la fonction appelée:

  • Le type de retour de la fonction est supposé être int
  • Tous les parameters sont supposés être déclarés (c’est-à-dire non ... vararg stuff)
  • Tous les parameters sont supposés correspondre à ce que vous passez après les promotions par défaut, etc.

Si la fonction appelée sans prototype correspond à ces hypothèses, votre programme s’exécutera correctement. sinon, c’est un comportement indéfini.

Avant la norme ANSI C de 1989, il n’existait aucun moyen de déclarer une fonction et d’indiquer les types de ses parameters. Vous devez juste faire très attention à rendre chaque appel cohérent avec la fonction appelée, sans avertissement du compilateur si vous vous trompez (par exemple, passer un int à sqrt() ). En l’absence d’une déclaration visible, toute fonction que vous appelez était supposée renvoyer int ; c’était la règle “implicit”. De nombreuses fonctions standard retournent int , vous pouvez donc souvent vous en passer en omettant un #include .

La norme ANSI C de 1989 (qui est aussi essentiellement la norme ISO C de 1990) a introduit des prototypes, mais ne les a pas rendus obligatoires (et ils ne le sont toujours pas). Donc si vous appelez

 int c = getchar(); 

cela fonctionnerait réellement, car getchar() renvoie un int .

La norme ISO C de 1999 a abandonné la règle implicite int et a rendu illégale (en réalité une violation de contrainte ) l’appel d’une fonction sans déclaration visible. Donc, si vous appelez une fonction standard sans le #include requirejs, un compilateur conforme à C99 doit émettre un diagnostic (qui peut n’être qu’un avertissement). Les déclarations de fonctions non prototypes (celles qui ne spécifient pas les types des arguments) sont toujours légales, mais elles sont considérées comme obsolètes.

(La norme ISO C de 2011 n’a pas beaucoup changé dans ce domaine particulier.)

Mais il rest encore beaucoup de code écrit pour les compilateurs C90, et la plupart des compilateurs modernes prennent encore en charge l’ancien standard.

Donc, si vous appelez une fonction standard sans le #include requirejs, ce qui va probablement arriver, c’est que (a) le compilateur vous préviendra de la déclaration manquante et (b) qu’il supposera que la fonction renvoie int et prend le nombre et le type qui conviennent. (s) des arguments que vous avez réellement passés (compte également pour le type promotion, tel que short to int et float to double ). Si l’appel est correct et si le compilateur est indulgent, votre code fonctionnera probablement, mais vous aurez une dernière chose à craindre en cas d’échec, peut-être pour une raison non liée.

Les fonctions variées comme printf sont un autre problème. Même en C89 / C90, l’appel de printf sans prototype visible avait un comportement indéfini. Un compilateur peut utiliser une convention d’appel totalement différente pour les fonctions variadiques. Par conséquent, printf("hello") et put puts("hello") peuvent générer un code très différent. Mais encore une fois, pour la compatibilité avec l’ancien code, la plupart des compilateurs utilisent une convention d’appel compatible. Ainsi, par exemple, le premier programme “hello world” de K & R1 sera probablement toujours compilé et exécuté.

Vous pouvez également écrire vos propres déclarations pour les fonctions standard. le compilateur ne se soucie pas de voir une déclaration dans un en-tête standard ou dans votre propre fichier source. Mais cela ne sert à rien. Les déclarations ont changé subtilement d’une version à l’autre de la norme et les en-têtes fournis avec votre implémentation doivent être les bons.

Alors que se passera-t-il si vous appelez une fonction standard sans le #include correspondant?

Dans un environnement de travail typique, cela n’a pas d’importance, car avec un peu de chance, votre programme ne survivra pas à la révision de code.

En principe, tout compilateur conforme à C99 ou à une version ultérieure peut rejeter votre programme avec un message d’erreur irrécupérable. (gcc se comportera de la sorte avec -std=c99 -pedantic-errors ) En pratique, la plupart des compilateurs afficheront simplement un avertissement. L’appel fonctionnera probablement si la fonction renvoie int (ou si vous ignorez le résultat) et si tous les types d’argument sont corrects. Si l’appel est incorrect, le compilateur peut ne pas être en mesure d’imprimer de bons diagnostics. Si la fonction ne renvoie pas int , le compilateur supposera probablement que c’est le cas et vous obtiendrez des résultats erronés, voire même vous bloquerez le programme.

Pour pouvoir étudier cette réponse, relisez-la en lisant les différentes versions de la norme C, déterminez à quelle édition de la norme votre compilateur est conforme et déterminez dans quelles circonstances vous pouvez omettre en toute sécurité un en-tête #include – avec le risque de gâcher quelque chose la prochaine fois que vous modifierez votre programme.

Vous pouvez également faire attention aux avertissements de votre compilateur (que vous avez activés avec les options de ligne de commande disponibles), lisez la documentation de chaque fonction que vous appelez, ajoutez les #include nécessaires en haut de chaque fichier source, et non avoir à se soucier de tout ça.

Tout d’abord: il suffit de les inclure.

Sinon, le compilateur utilisera le prototype par défaut pour les fonctions non déclarées, à savoir:

 int functionName(int argument); 

Donc, il va comstackr et lier si les fonctions sont disponibles. Mais vous aurez des problèmes au moment de l’exécution.

Il y a beaucoup de choses que vous ne pouvez pas faire si vous omettez les en-têtes:

(J’espère en savoir plus sur les commentaires car ma mémoire manque à ce sujet …)

  • Vous ne pouvez utiliser aucune des macros définies dans les en-têtes. Cela peut être important.
  • Le compilateur ne peut pas vérifier que vous appelez correctement les fonctions car les en-têtes définissent leurs parameters.

Pour assurer la compatibilité avec l’ancien programme, les compilateurs C peuvent comstackr des fonctions d’appel de code qui n’ont pas été déclarées, en supposant que les parameters et la valeur renvoyée soient de type int . Que peut-il arriver? Voir, par exemple, cette question: Troubler la conversion de chaîne en long en C Je pense que c’est une excellente illustration des problèmes que vous pouvez rencontrer si vous n’incluez pas les en-têtes nécessaires et ne déclarez pas les fonctions que vous utilisez. Ce qui est arrivé à ce type, c’est qu’il a essayé d’utiliser atoll sans inclure stdlib.hatoll est déclaré:

 char s[30] = { "115" }; long long t = atoll(s); printf("Value is: %lld\n", t); 

Étonnamment, cette impression 0 , pas 115 , comme prévu! Pourquoi? Parce que le compilateur n’a pas vu la déclaration d’ atoll et a supposé que sa valeur de retour est un int , il n’a donc sélectionné qu’une partie de la valeur laissée par la fonction, autrement dit, la valeur de retour a été tronquée.

C’est pourquoi il est recommandé de comstackr votre code avec -Wall (tous les avertissements sont activés).