En C, no noté ningún efecto de la extern
palabra clave utilizada antes de la declaración de la función. Al principio, pensé que al definir extern int f();
en un solo archivo te obliga a implementarlo fuera del alcance del archivo. Sin embargo descubrí que ambos:
extern int f();
int f() {return 0;}
y
extern int f() {return 0;}
compila muy bien, sin advertencias de gcc. Solía gcc -Wall -ansi
; Ni siquiera aceptaría //
comentarios.
¿Hay algún efecto por usar extern
antes las definiciones de funciones ? ¿O es solo una palabra clave opcional sin efectos secundarios para las funciones?
En este último caso, no entiendo por qué los diseñadores estándar eligieron llenar la gramática con palabras clave superfluas.
EDIT: Para aclarar, sé que hay para el uso extern
en las variables, pero yo sólo estoy preguntando extern
en funciones .
Respuestas:
Tenemos dos archivos, foo.c y bar.c.
Aquí está foo.c
Ahora, aquí está bar.c
Como puede ver, no tenemos un encabezado compartido entre foo.c y bar.c, sin embargo, bar.c necesita algo declarado en foo.c cuando está vinculado, y foo.c necesita una función de bar.c cuando está vinculado.
Al usar 'extern', le está diciendo al compilador que lo que sigue se encontrará (no estático) en el momento del enlace; no reserve nada para ello en el pase actual, ya que se encontrará más adelante. Las funciones y variables se tratan por igual en este sentido.
Es muy útil si necesita compartir algo global entre módulos y no desea ponerlo / inicializarlo en un encabezado.
Técnicamente, cada función en el encabezado público de una biblioteca es 'externa', sin embargo, etiquetarlas como tales tiene muy poco o ningún beneficio, dependiendo del compilador. La mayoría de los compiladores pueden resolverlo solos. Como puede ver, esas funciones están definidas en otro lugar.
En el ejemplo anterior, main () imprimiría hello world solo una vez, pero continuaría ingresando bar_function (). También tenga en cuenta que bar_function () no va a volver en este ejemplo (ya que es solo un ejemplo simple). Imagínense que stop_now se modifica cuando se da servicio a una señal (por lo tanto, volátil) si esto no parece lo suficientemente práctico.
Los patrones son muy útiles para cosas como manejadores de señal, un mutex que no desea poner en un encabezado o estructura, etc. La mayoría de los compiladores se optimizarán para garantizar que no reserven memoria para objetos externos, ya que saben que Lo reservaremos en el módulo donde se define el objeto. Sin embargo, de nuevo, no tiene mucho sentido especificarlo con compiladores modernos al crear prototipos de funciones públicas.
Espero que ayude :)
fuente
bar.c
y la declaración enfoo.c
. Si la función se declara enfoo.h
y ambos archivos incluyenfoo.h
, entonces el encabezado impone coherencia entre los dos archivos de origen. Sin ella, si la definición debar_function
inbar.c
cambia pero la declaraciónfoo.c
no cambia, entonces las cosas salen mal en tiempo de ejecución; El compilador no puede detectar el problema. Con un encabezado utilizado correctamente, el compilador detecta el problema.Hasta donde recuerdo el estándar, todas las declaraciones de funciones se consideran como "externas" de forma predeterminada, por lo que no es necesario especificarlo explícitamente.
Eso no hace que esta palabra clave sea inútil ya que también se puede usar con variables (y en ese caso, es la única solución para resolver problemas de vinculación). Pero con las funciones, sí, es opcional.
fuente
Debe distinguir entre dos conceptos separados: definición de función y declaración de símbolo. "extern" es un modificador de vinculación, una pista para el compilador acerca de dónde se define el símbolo al que se hace referencia después (la pista es "no aquí").
Si yo escribo
en el alcance del archivo (fuera de un bloque de funciones) en un archivo C, entonces usted dice "la variable puede estar definida en otro lugar".
es tanto una declaración de la función f como una definición de la función f. La definición en este caso anula la externa.
es primero una declaración, seguida de la definición.
El uso de
extern
es incorrecto si desea declarar y definir simultáneamente una variable de alcance de archivo. Por ejemplo,dará un error o advertencia, dependiendo del compilador.
El uso de
extern
es útil si desea explícitamente evitar la definición de una variable.Dejame explicar:
Digamos que el archivo ac contiene:
El archivo ah incluye:
y el archivo bc contiene:
El extern en el encabezado es útil, porque le dice al compilador durante la fase de enlace, "esto es una declaración, y no una definición". Si elimino la línea en ac que define i, le asigna espacio y le asigna un valor, el programa no podrá compilarse con una referencia indefinida. Esto le dice al desarrollador que se ha referido a una variable, pero que aún no la ha definido. Si, por otro lado, omito la palabra clave "extern" y elimino la
int i = 2
línea, el programa aún se compila; se definirá con un valor predeterminado de 0.Las variables de alcance de archivo se definen implícitamente con un valor predeterminado de 0 o NULL si no les asigna explícitamente un valor, a diferencia de las variables de alcance de bloque que declara en la parte superior de una función. La palabra clave externa evita esta definición implícita y, por lo tanto, ayuda a evitar errores.
Para las funciones, en las declaraciones de funciones, la palabra clave es de hecho redundante. Las declaraciones de funciones no tienen una definición implícita.
fuente
int i = 2
línea en el tercer párrafo? ¿Y es correcto decir, viendoint i;
, el compilador asignará memoria para esa variable, pero viendoextern int i;
, el compilador NO asignará memoria sino que buscará la variable en otra parte?La
extern
palabra clave adquiere diferentes formas según el entorno. Si hay una declaración disponible, laextern
palabra clave toma el enlace como se especificó anteriormente en la unidad de traducción. En ausencia de dicha declaración,extern
especifica el enlace externo.Estos son los párrafos relevantes del borrador C99 (n1256):
fuente
Las funciones en línea tienen reglas especiales sobre lo que
extern
significa. (Tenga en cuenta que las funciones en línea son una extensión C99 o GNU; no estaban en C. originalPara funciones no en línea,
extern
no es necesario ya que está activado de forma predeterminada.Tenga en cuenta que las reglas para C ++ son diferentes. Por ejemplo,
extern "C"
es necesario en la declaración de C ++ de las funciones de C a las que va a llamar desde C ++, y existen diferentes reglas al respectoinline
.fuente
Por eso, 10 años después:
extern
en la declaración de función para su eliminación;git/git
sigue esa conclusión y lo eliminaextern
de su código (para Git 2.22, Q2 2019).Ver commit ad6dad0 , commit b199d71 , commit 5545442 (29 abr 2019) por Denton Liu (
Denton-L
) .(Fusionada por Junio C Hamano -
gitster
- en commit 4aeeef3 , 13 de mayo de 2019)Sin embargo, esto no siempre es sencillo:
Ver commit 7027f50 (04 Sep 2019) por Denton Liu (
Denton-L
) .(Fusionada por Denton Liu -
Denton-L
- en commit 7027f50 , 05 sep 2019)Tenga en cuenta que con Git 2.24 (Q4 2019), se elimina cualquier espuria
extern
.Ver commit 65904b8 (30 Sep 2019) por Emily Shaffer (
nasamuffin
) .Ayudado por: Jeff King (
peff
) .Ver commit 8464f94 (21 Sep 2019) por Denton Liu (
Denton-L
) .Ayudado por: Jeff King (
peff
) .(Fusionada por Junio C Hamano -
gitster
- en commit 59b19bc , 07 oct 2019)fuente
La
extern
palabra clave informa al compilador que la función o variable tiene un enlace externo; en otras palabras, que es visible desde archivos distintos de aquel en el que está definida. En este sentido tiene el significado opuesto a lastatic
palabra clave. Es un poco extraño ponerloextern
en el momento de la definición, ya que ningún otro archivo tendría visibilidad de la definición (o daría lugar a múltiples definiciones). Normalmente colocaextern
una declaración en algún momento con visibilidad externa (como un archivo de encabezado) y coloca la definición en otro lugar.fuente
declarar una función externa significa que su definición se resolverá en el momento del enlace, no durante la compilación.
A diferencia de las funciones regulares, que no se declaran externas, se puede definir en cualquiera de los archivos de origen (pero no en varios archivos de origen, de lo contrario, obtendrá un error de enlace que indica que ha dado varias definiciones de la función), incluida la de que se declara externa. Entonces, en su caso, el vinculador resuelve la definición de la función en el mismo archivo.
No creo que hacer esto sea muy útil, sin embargo, hacer este tipo de experimentos da una mejor idea de cómo funciona el compilador y el enlazador del lenguaje.
fuente
La razón por la que no tiene ningún efecto es porque en el momento del enlace el enlazador intenta resolver la definición externa (en su caso
extern int f()
). No importa si lo encuentra en el mismo archivo o en un archivo diferente, siempre que se encuentre.Espero que esto responda a su pregunta.
fuente
extern
a cualquier función?