¿Por qué no se requiere #include <stdio.h> para usar printf()?

¿Por qué no se requiere #include <stdio.h> para usar printf()?


Transcripción de la sesión:


> 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

Respuestas:


En el modo de cumplimiento estricto (que significa "en teoría"), invoca un comportamiento indefinido (lo cual es malo) cuando llama a una función que toma una cantidad variable de argumentos sin una declaración de prototipo de la función en el alcance. Eso significa que el compilador puede hacer lo que quiera con un programa que usa printf() sin el prototipo de #include <stdio.h> o una declaración equivalente. "Todo lo que le gusta" incluye el funcionamiento correcto como una de las opciones; esa parece ser la opción elegida por su ejemplo.


En la práctica, el código funcionará bien con la mayoría de los compiladores prácticos incluso sin la declaración formal del printf() función.


Como señaló qrdl, la función se encontró porque el compilador de C se vincula con la biblioteca de C.


Tenga en cuenta que el comentario de Chris Young sobre C99 y 'int implícito' es preciso, pero la regla sobre 'las funciones de argumentos variables deben tener un prototipo en el alcance' se aplica tanto a C89 como a C99. La mayoría de los compiladores no funcionan en un modo de compatibilidad estricto con C99 de forma predeterminada porque hay demasiado código que no compilaría así.


Chris Young comentó:



Chris, por supuesto, tiene razón. Se eliminaron dos características de 'declaración implícita' del estándar C99. El prólogo de la norma los enumera como:



  • eliminar implícito int

  • eliminar declaración de función implícita


No estaba pensando (y por lo tanto no estaba escribiendo) con la suficiente claridad. Sin embargo, tanto C89 como C99 requieren un prototipo en el ámbito de las funciones que toman un número variable de argumentos.


Para ilustrar:


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

Sin la primera línea, este es un fragmento C89 correcto con una declaración implícita de la función pqr() como una función que devuelve un número entero (con argumentos no especificados). Si la primera línea se reemplaza por extern pqr(); , entonces este es un fragmento C89 correcto con una declaración explícita de pqr() como una función que devuelve un número entero (con argumentos no especificados), pero el tipo de retorno es 'implícito int '. Tal como está escrito, la función se declara explícitamente y tiene un int explícito tipo de retorno, pero todavía tiene argumentos no especificados. Creo que es C99 válido, aunque no del todo deseable. Ciertamente, GCC (3.4.4) lo acepta con las opciones '-std=c99 -pedantic ". Idealmente, la declaración de la función debería incluir el prototipo completo. (Y, si pqr() se definieron con puntos suspensivos, ese prototipo sería necesario en teoría !)