Declaraciones de funciones implícitas en C
(6)
C es un lenguaje de muy bajo nivel, por lo que le permite crear casi cualquier archivo de objeto legal (.o) que pueda concebir. Deberías pensar en C como un lenguaje ensamblador básicamente disfrazado.
En particular, C no requiere que se declaren las funciones antes de que se utilicen. Si llama a una función sin declararla, el uso de la función se convierte en su declaración (implícita). En una prueba simple que acabo de ejecutar, esta es solo una advertencia en el caso de funciones de biblioteca incorporadas como printf (al menos en GCC), pero para funciones aleatorias, se compilará muy bien.
Por supuesto, cuando intentas vincular, y no puede encontrar a foo, entonces obtendrás un error.
En el caso de las funciones de biblioteca como printf, algunos compiladores contienen declaraciones incorporadas para que puedan hacer una comprobación básica de tipo, de modo que cuando la declaración implícita (del uso) no coincida con la declaración incorporada, usted recibe una advertencia.
Qué significa el término "declaración implícita de una función". La llamada a la función de biblioteca estándar sin incluir el archivo de encabezado apropiado produce una advertencia como en el caso de
int main(){
printf("How is this not an error ?");
return 0;
}
¿No debería usar una función sin declarar que es un error? Por favor explique en detalle. Busqué en este sitio y encontré preguntas similares, pero no pude encontrar una respuesta definitiva. La mayoría de las respuestas dicen algo sobre incluir el archivo de encabezado para deshacerse de la advertencia. Pero quiero saber cómo es que esto no es un error.
Debe ser considerado un error. Pero C es un idioma antiguo, por lo que es solo una advertencia.
La -Werror
con -Werror
(gcc) corrige este problema.
Cuando C no encuentra una declaración, asume esta declaración implícita: int f();
, lo que significa que la función puede recibir lo que sea que le des, y devuelve un número entero. Si esto sucede lo suficientemente cerca (y en caso de printf
, es), entonces las cosas pueden funcionar. En algunos casos (por ejemplo, la función realmente devuelve un puntero, y los punteros son más grandes que las iniciales), puede causar problemas reales.
Tenga en cuenta que esto se corrigió en los estándares C más nuevos (C99, C11). En estos estándares, esto es un error. Sin embargo, gcc
no implementa estos estándares de forma predeterminada, por lo que aún recibe la advertencia.
Debido a razones históricas que se remontan a la primera versión de C, se supone que las funciones tienen una definición implícita de int function(int arg1, int arg2, int arg3, etc)
.
Editar: no, estaba equivocado sobre int
para los argumentos. En cambio, pasa el tipo de argumento que sea. Entonces podría ser un int
o un double
o un char*
. Sin un prototipo, el compilador pasará el tamaño del argumento y la función a la que se llama utilizará mejor el tipo de argumento correcto para recibirlo.
Para más detalles, busque K&R C
Las declaraciones implícitas no son válidas en C.
C99 eliminó esta característica (presente en C89).
gcc
elige emitir una advertencia de manera predeterminada con -std=c99
pero un compilador tiene derecho a negarse a traducir dicho programa.
Para completar la imagen, ya que -Werror
podría considerarse demasiado "invasivo",
para gcc (y llvm) una solución más precisa es transformar solo esta advertencia en un error, usando la opción:
-Werror=implicit-function-declaration
Consulte ¿ Hacer que un gcc advierta un error?
En cuanto al uso general de -Werror
: por supuesto, es recomendable tener un código sin advertencias, pero en alguna etapa de desarrollo podría ralentizar la creación de prototipos.
Una función implícitamente declarada es aquella que no tiene ni un prototipo ni una definición, pero se llama en algún lugar del código. Debido a eso, el compilador no puede verificar que este sea el uso previsto de la función (si el recuento y el tipo de los argumentos coinciden). La resolución de las referencias se realiza después de la compilación, en tiempo de enlace (como con todos los demás símbolos globales), por lo que técnicamente no es un problema omitir el prototipo.
Se supone que el programador sabe lo que está haciendo y esta es la premisa bajo la cual se omite el contrato formal de proporcionar un prototipo.
Errores desagradables pueden suceder si llama a la función con argumentos de un tipo o conteo incorrectos. La manifestación más probable de esto es una corrupción de la pila.
Hoy en día, esta característica puede parecer una rareza oscura, pero en los viejos tiempos era una forma de reducir el número de archivos de encabezado incluidos, por lo tanto, una compilación más rápida.