Pourquoi #include n’est pas obligé d’utiliser printf ()?

Transcription de session:

>type lookma.c int main() { printf("%s", "no stdio.h"); } >cl lookma.c Microsoft (R) 32-bit C/C++ Optimizing Comstackr Version 14.00.50727.762 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. lookma.c Microsoft (R) Incremental Linker Version 8.00.50727.762 Copyright (C) Microsoft Corporation. All rights reserved. /out:lookma.exe lookma.obj >lookma no stdio.h 

En mode de conformité ssortingct (ce qui signifie “en théorie”), vous appelez un comportement indéfini (ce qui est mauvais) lorsque vous appelez une fonction qui prend un nombre variable d’arguments sans déclaration prototype de la fonction dans la scope. Cela signifie que le compilateur est autorisé à faire ce qu’il veut avec un programme qui utilise printf() sans le prototype de #include ou une déclaration équivalente. “Tout ce qu’il aime” comprend le fait de fonctionner correctement comme l’une des options; cela semble être l’option choisie par votre exemple.

En pratique, le code fonctionnera correctement avec la plupart des compilateurs pratiques, même sans la déclaration formelle de la fonction printf() .

Comme l’a souligné qrdl, la fonction a été trouvée car le compilateur C est lié à la bibliothèque C.

Notez que le commentaire de Chris Young à propos de C99 et de “implicit int” est exact, mais que la règle concernant les “fonctions d’arguments variables doit avoir un prototype dans la scope” s’applique à la fois à C89 et à C99. La plupart des compilateurs ne fonctionnent pas dans un mode de compatibilité C99 ssortingct par défaut car il y a trop de code qui ne comstackrait pas comme ça.

Chris Young a commenté:

Pour clarifier, mon commentaire concernait le retrait de la déclaration implicite par le C99. En disant “implicit int”, je pense que vous faites référence à la fonctionnalité C89 consistant à autoriser des déclarations telles que foo (void); signifie int foo (vide); quelque chose de C99 a également été supprimé.

Chris a bien sûr raison. Deux fonctionnalités de «déclaration implicite» ont été supprimées de la norme C99. L’avant-propos de la norme les répertorie comme suit:

  • enlever int implicite
  • supprimer la déclaration de fonction implicite

Je ne pensais pas (et donc n’écrivais pas) assez clairement. Néanmoins, C89 et C99 requièrent tous deux un prototype pour les fonctions utilisant un nombre variable d’arguments.

Pour illustrer:

 extern int pqr(); int main(void) { int i = pqr(1, 3); return i; } 

Sans la première ligne, il s’agit d’un fragment C89 correct avec une déclaration implicite de la fonction pqr() tant que fonction pqr() un entier (avec des arguments non spécifiés). Si la première ligne est remplacée par extern pqr(); alors c’est un fragment C89 correct avec une déclaration explicite de pqr() tant que fonction pqr() un entier (avec des arguments non spécifiés), mais le type de retour est ‘implicit int ‘. Comme écrit, la fonction est explicitement déclarée et possède un type de retour int explicite – mais elle a toujours des arguments non spécifiés. Je crois que cela est valable C99 – bien que ce ne soit pas totalement souhaitable. Certes, GCC (3.4.4) l’accepte avec les options ‘ -std=c99 -pedantic “. Idéalement, la déclaration de fonction devrait inclure le prototype complet. (Et, si pqr() était défini avec des points de suspension, ce prototype serait requirejs en théorie !)

Vous aviez initialement étiqueté ce C ++, mais il semblerait que ce soit un programme C. C fournira automatiquement une déclaration implicite pour une fonction s’il n’y a pas de prototype dans la scope (par exemple, en raison de l’omission de #include ). La déclaration implicite serait:

 int printf(); 

Ce qui signifie que printf est une fonction qui retourne un int et peut prendre un nombre quelconque d’arguments. Ce prototype est arrivé à travailler pour votre appel. Vous devriez #include

Enfin, je devrais append que la norme C actuelle (ISO / IEC 9899: 1999 ou familièrement “C99”) n’autorise pas les déclarations implicites et que ce programme ne serait pas conforme. Les déclarations implicites ont été supprimées. Je crois que votre compilateur ne supporte pas C99. C ++ requirejs également des prototypes corrects et ne fait pas de déclarations implicites.

printf() est situé dans la bibliothèque standard C et l’éditeur de liens lie toujours la bibliothèque standard à votre exécutable, ainsi toutes les fonctions standard seront trouvées et il n’y aura pas de problèmes de liaison.

Ne pas inclure les en-têtes appropriés entraîne l’utilisation d’une fonction non prototypée pouvant entraîner des problèmes, car le compilateur C suppose que cette fonction sans prototype renvoie int et prend un nombre variable d’arguments. Donc, toujours inclure l’en-tête – c’est votre barrière de sécurité.