web-dev-qa-db-fra.com

Pourquoi #include <stdio.h> n'est pas requis pour utiliser printf ()?

Transcription de la session:

>type lookma.c
int main() {
  printf("%s", "no stdio.h");
}

>cl lookma.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler 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
30
Constantin

En mode de conformité strict (cela signifie "en théorie"), vous invoquez un comportement non défini (qui est mauvais) lorsque vous appelez une fonction qui prend un nombre variable d'arguments sans déclaration de prototype de la fonction dans la portée. Cela signifie que le compilateur est autorisé à faire tout ce qu'il aime avec un programme utilisant printf() sans le prototype de #include <stdio.h> Ou une déclaration équivalente. "Tout ce qu'il aime" inclut la fonction de travail 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 cela a été souligné par QRDL, la fonction a été trouvée parce que le compilateur C avec la bibliothèque C.

Notez que le commentaire de Chris Young sur C99 et "Implicit Int" est précis, mais la règle des "fonctions variables des arguments doit disposer d'un prototype de portée" s'applique à la fois à C89 et en C99. La plupart des compilateurs ne fonctionnent pas dans un mode de compatibilité C99 strict par défaut car il y a trop de code qui ne compilerait pas comme ça.

Chris Young a commenté:

Pour clarifier, mon commentaire était sur C99 en supprimant les déclarations implicites. En disant "INT implicite", je pense que vous vous référez à la caractéristique C89 de permettre des déclarations telles que FOO (VOID); signifier INT FOO (vide); quelque chose C99 a également supprimé.

Chris est bien sûr correct. Il y avait deux caractéristiques "Déclaration implicite" retirées de la norme C99. L'avant-propos de la norme les énumère comme suit:

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

Je ne pensais pas (et donc pas écrire) assez clairement. Néanmoins, C89 et C99 nécessitent un prototype de possibilités de fonctions qui prennent un nombre variable d'arguments.

Pour illustrer:

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

Sans première ligne, il s'agit d'un fragment C89 correct avec une déclaration implicite de la fonction pqr() comme fonction qui renvoie un entier (avec des arguments non spécifiés). Si la première ligne est remplacée par extern pqr();, il s'agit donc d'un fragment C89 correct avec une déclaration explicite de pqr() comme fonction qui renvoie un entier (avec des arguments non spécifiés), mais le retour Type est 'implicite int'. Comme écrit, la fonction est explicitement déclarée et dispose d'un type de retour int - mais il a toujours des arguments non spécifiés. Je crois que c'est valable C99 - bien que peu souhaitables. Certainement, GCC (3.4.4) l'accepte avec les options '-std=c99 -pedantic ". Idéalement, la déclaration de fonction doit inclure le prototype complet. (Et si pqr() a été définie avec des ellipsis, que Le prototype serait requis en théorie!)

32
Jonathan Leffler

Vous avez initialement marqué ce C++, mais cela semblerait être un programme C. C fournira automatiquement une déclaration implicite pour une fonction s'il n'y a pas de prototype de portée (comme en raison de l'omission de #include <stdio.h>). La déclaration implicite serait:

int printf();

Ce qui signifie que PrintF est une fonction qui renvoie un Int et peut prendre n'importe quel nombre d'arguments. Ce prototype a eu lieu pour votre appel. Vous devriez #include <stdio.h>

Enfin, je devrais ajouter que la norme C actuelle C (ISO/CEI 9899: 1999 ou "C99"), PAS Autoriser les déclarations implicites, et ce programme ne serait pas conforme. Les déclarations implicites ont été supprimées. Je crois que votre compilateur ne prend pas en charge C99. C++ nécessite également des prototypes corrects et ne fait pas de déclarations implicites.

37
Chris Young

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

Le défaut d'inclure l'en-tête approprié entraîne l'utilisation de la fonction qui n'était pas prototypée pouvant entraîner des problèmes, car le compilateur C suppose que la fonction sans prototype renvoie int et prend un nombre variable d'arguments. Incluez donc toujours l'en-tête - c'est votre clôture de sécurité.

9
qrdl