Declaraciones de funciones implícitas en C

7 minutos de lectura

avatar de usuario
Bazuca

¿Qué significa el término “declaración implícita de una función”? Una llamada a una 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 ser un error usar una función sin declararla? 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 dijeron algo sobre incluir el archivo de encabezado para eliminar la advertencia, pero quiero saber cómo esto no es un error.

  • La biblioteca C estándar está vinculada de forma predeterminada a las compilaciones; por ejemplo, con gcc tiene que pasar explícitamente -nostdlib como argumento a la compilación para obligarla a no vincularse con libc.

    – bert

    7 febrero 2012 a las 19:50

  • @tbert Es por eso que el enlazador no se queja, pero el enlazador tiene un efecto muy pequeño en lo que hace el compilador con el código C.

    usuario395760

    7 febrero 2012 a las 19:51

  • Consulte también stackoverflow.com/questions/22500/…

    – Zan Lince

    7 febrero 2012 a las 19:51

  • Busqué K&R y dice que si no hay una declaración previa de la función visible en el alcance, se supone que la primera instancia de uso de funciones es una declaración con tipo de retorno int y no se asume nada sobre los parámetros. Gracias por su entrada a todos.

    – Bazuca

    7 febrero 2012 a las 20:19

  • posible duplicado de ¿Se requieren prototipos para todas las funciones en C89, C90 o C99?

    – Ciro Santilli Путлер Капут 六四事

    13 de mayo de 2015 a las 7:26

avatar de usuario
ugoren

Debe considerarse un error. Pero C es un idioma antiguo, por lo que es solo una advertencia.
Compilando con -Werror (gcc) soluciona 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 le des y devuelve un número entero. Si esto sucede lo suficientemente cerca (y en caso de printf, lo es), entonces las cosas pueden funcionar. En algunos casos (por ejemplo, la función en realidad devuelve un puntero y los punteros son más grandes que los enteros), puede causar problemas reales.

Tenga en cuenta que esto se solucionó 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.

  • Su respuesta es correcta y dice exactamente lo que dice K&R. Gracias por la explicación concisa.

    – Bazuca

    7 febrero 2012 a las 20:22

  • Tenga en cuenta que incluso en los días en que se permitían las declaraciones implícitas, todavía daban como resultado UB para funciones variádicas como printf.

    – R.. GitHub DEJA DE AYUDAR A ICE

    7 febrero 2012 a las 23:42

  • @R.., en principio tienes razón. En la práctica, la mayoría de las implementaciones manejan una función variable con n parámetros como una función normal que tiene n parámetros, por lo que todo funciona.

    – ugoren

    8 de febrero de 2012 a las 5:35

  • Esta respuesta fue correcta hace 24 años. Está mal hoy. El estándar C actual (C11) y el anterior ampliamente implementado (C99) prohíben explícitamente llamar a funciones no declaradas.

    usuario529758

    1 de diciembre de 2013 a las 0:11

  • @ugoren Un compilador demasiado popular, clang por defecto es C99, otro muy importante, gcc, lo apoya. El único compilador ampliamente utilizado en el mercado, MSVC de Microsoft, es el único que no tiene soporte para C89. Entonces, “los compiladores no usan estándares más nuevos” no es cierto.

    usuario529758

    1 de diciembre de 2013 a las 8:36

Las declaraciones implícitas no son válidas en C.

C99 eliminó esta función (presente en C89).

gcc elige emitir solo una advertencia por defecto con -std=c99 pero un compilador tiene derecho a negarse a traducir dicho programa.

  • En una nota relacionada, -pedantic-errors hará que GCC (o CLang, para el caso) se comporte según el estándar aquí, y se negará a compilar (léase: emitir un error y cancelar).

    – Tim Cas

    10 de febrero de 2015 a las 20:12

avatar de usuario
Blagovest Büyükliev

Una función declarada implícitamente es aquella que no tiene prototipo ni definición, pero se llama en alguna parte del código. Por 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 a él 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 hace y esta es la premisa bajo la cual se omite el contrato formal de suministro de un prototipo.

Pueden ocurrir errores desagradables si se llama a la función con argumentos de un tipo o recuento incorrecto. 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 extraña rareza, pero en los viejos tiempos era una forma de reducir la cantidad de archivos de encabezado incluidos, por lo tanto, una compilación más rápida.

  • Cita necesaria. No se incluyeron declaraciones implícitas como una característica para mejorar el tiempo de compilación. Por lo que puedo decir, la evolución temprana de C (desde B) comenzó sin tipos pero inty por lo tanto conocer la información de tipo sobre una función no era tan importante…

    – R.. GitHub DEJA DE AYUDAR A ICE

    7 febrero 2012 a las 23:44

  • donde dices “prototipo” quieres decir “declaración”. Algunas declaraciones no son prototipos.

    –MM

    31 de enero de 2017 a las 1:52


avatar de usuario
zan lince

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).

Edit: no, me equivoqué int por los argumentos. En su lugar, pasa cualquier tipo de argumento. Así que podría ser un int o un double o un char*. Sin un prototipo, el compilador pasará el tamaño del argumento y será mejor que la función que se llama use el tipo de argumento correcto para recibirlo.

Para más detalles mira hacia arriba K&R C.

  • Más bien, simplemente silencie a los molestos de -Werror.

    – Antti Haapala — Слава Україні

    2 de marzo de 2017 a las 11:57

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ía pensar en C como un lenguaje ensamblador básicamente disfrazado.

En particular, C no requiere que se declaren las funciones antes de usarlas. 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, esto es solo una advertencia en el caso de funciones de biblioteca integradas como printf (al menos en GCC), pero para funciones aleatorias, se compilará bien.

Por supuesto, cuando intenta vincular y no puede encontrar foo, obtendrá un error.

En el caso de funciones de biblioteca como printf, algunos compiladores contienen declaraciones integradas para ellos, de modo que pueden realizar una verificación de tipo básica, de modo que cuando la declaración implícita (del uso) no coincida con la declaración integrada, recibir una advertencia.

  • ¿Alguna idea de por qué gcc lo hace para “funciones integradas” como printf? Parece que funciona bien con las funciones definidas por el usuario.

    – Bazuca

    7 febrero 2012 a las 20:34


  • “En particular, C no requiere que se declaren las funciones antes de que se usen”. – lo hace. C89 (que permitió esto) no es el estándar actual. C11 lo es, y ni C11 ni su predecesor demasiado popular, C99, permiten llamar a funciones declaradas implícitamente.

    usuario529758

    1 de diciembre de 2013 a las 0:13

  • ¿Alguna idea de por qué gcc lo hace para “funciones integradas” como printf? Parece que funciona bien con las funciones definidas por el usuario.

    – Bazuca

    7 febrero 2012 a las 20:34


  • “En particular, C no requiere que se declaren las funciones antes de que se usen”. – lo hace. C89 (que permitió esto) no es el estándar actual. C11 lo es, y ni C11 ni su predecesor demasiado popular, C99, permiten llamar a funciones declaradas implícitamente.

    usuario529758

    1 de diciembre de 2013 a las 0:13

¿Ha sido útil esta solución?