Efectos de la palabra clave extern en las funciones de C

Efectos de la palabra clave extern en las funciones de C

Tenemos dos archivos, foo.c y bar.c.

Aquí está foo.c

#include <stdio.h>

volatile unsigned int stop_now = 0;
extern void bar_function(void);

int main(void)
{
  while (1) {
     bar_function();
     stop_now = 1;
  }
  return 0;
}

Ahora, aquí está bar.c

#include <stdio.h>

extern volatile unsigned int stop_now;

void bar_function(void)
{
   if (! stop_now) {
      printf("Hello, world!\n");
      sleep(30);
   }
}

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 todo lo que sigue se encontrará (no estático) en el momento del enlace; no le reserve nada en el pase actual, ya que se encontrará más adelante. Las funciones y las variables se tratan por igual en este sentido.

Es muy útil si necesita compartir algo global entre módulos y no quiere 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, según el compilador. La mayoría de los compiladores pueden darse cuenta de eso por sí mismos. Como puede ver, esas funciones en realidad están definidas en otro lugar.

En el ejemplo anterior, main() imprimiría hola mundo solo una vez, pero continuaría ingresando bar_function(). También tenga en cuenta que bar_function() no regresará en este ejemplo (ya que es solo un ejemplo simple). Solo imagine que stop_now se modifica cuando se atiende una señal (por lo tanto, volátil) si esto no parece lo suficientemente práctico.

Los externos son muy útiles para cosas como controladores de señales, un mutex que no desea colocar en un encabezado o estructura, etc. La mayoría de los compiladores optimizarán para garantizar que no reserven memoria para objetos externos, ya que saben que Lo estarás reservando en el módulo donde se define el objeto. Sin embargo, nuevamente, no tiene mucho sentido especificarlo con compiladores modernos cuando se crean prototipos de funciones públicas.

Espero que ayude :)


Por lo que recuerdo del estándar, todas las declaraciones de funciones se consideran "externas" de forma predeterminada, por lo que no es necesario especificarlas 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.


Debe distinguir entre dos conceptos separados:definición de función y declaración de símbolo. "extern" es un modificador de enlace, una pista para el compilador sobre dónde se define el símbolo al que se hace referencia después (la pista es "no aquí").

Si escribo

extern int i;

en el alcance del archivo (fuera de un bloque de funciones) en un archivo C, entonces está diciendo "la variable puede definirse en otro lugar".

extern int f() {return 0;}

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.

extern int f();
int f() {return 0;}

es primero una declaración, seguida de la definición.

Uso de extern es incorrecto si desea declarar y definir simultáneamente una variable de ámbito de archivo. Por ejemplo,

extern int i = 4;

dará un error o una advertencia, dependiendo del compilador.

Uso de extern es útil si desea evitar explícitamente la definición de una variable.

Déjame explicarte:

Digamos que el archivo a.c contiene:

#include "a.h"

int i = 2;

int f() { i++; return i;}

El archivo a.h incluye:

extern int i;
int f(void);

y el archivo b.c contiene:

#include <stdio.h>
#include "a.h"

int main(void){
    printf("%d\n", f());
    return 0;
}

El extern en el encabezado es útil porque le dice al compilador durante la fase de enlace, "esto es una declaración, no una definición". Si elimino la línea en a.c que define i, le asigna espacio y le asigna un valor, el programa debería fallar al compilar con una referencia indefinida. Esto le dice al desarrollador que se ha referido a una variable, pero aún no la ha definido. Si, por el contrario, omito la palabra clave "extern" y elimino el 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 un valor explícitamente, a diferencia de las variables de alcance de bloque que declara en la parte superior de una función. La palabra clave extern evita esta definición implícita y, por lo tanto, ayuda a evitar errores.

Para funciones, en declaraciones de funciones, la palabra clave es redundante. Las declaraciones de funciones no tienen una definición implícita.