Mi pregunta es sobre cuándo se debe hacer referencia a una función con la extern
palabra clave en C.
No veo cuándo se debe usar esto en la práctica. Mientras escribo un programa, todas las funciones que uso están disponibles a través de los archivos de encabezado que he incluido. Entonces, ¿por qué sería útil extern
obtener acceso a algo que no estaba expuesto en el archivo de encabezado?
Podría estar pensando en cómo extern
funciona incorrectamente, y si es así, corrígeme.
Editar: ¿Debería hacer extern
algo cuando es la declaración predeterminada sin la palabra clave en un archivo de encabezado?
Respuestas:
"
extern
" cambia el enlace. Con la palabra clave, se supone que la función / variable está disponible en otro lugar y la resolución se difiere al vinculador.Hay una diferencia entre "externo" en las funciones y en las variables: en las variables no crea una instancia de la variable en sí misma, es decir, no asigna memoria. Esto debe hacerse en otro lugar. Por lo tanto, es importante si desea importar la variable desde otro lugar. Para funciones, esto solo le dice al compilador que el enlace es externo. Como este es el valor predeterminado (usa la palabra clave "estática" para indicar que una función no está vinculada mediante un enlace externo), no necesita usarla explícitamente.
fuente
extern le dice al compilador que estos datos se definen en algún lugar y se conectarán con el enlazador.
Con la ayuda de las respuestas aquí y hablar con algunos amigos aquí es el ejemplo práctico de un uso de extern .
Ejemplo 1 - para mostrar una trampa:
Si myCFile1.o y myCFile2.o están vinculados, cada uno de los archivos c tiene copias separadas de errno . Este es un problema ya que se supone que el mismo error está disponible en todos los archivos vinculados.
Ejemplo 2 - La solución.
Ahora, si myCFile1.o y MyCFile2.o están vinculados por el vinculador, ambos apuntarán al mismo error . Así, resolviendo la implementación con extern .
fuente
-Wall
y-pedantic
. Por qué ? y cómo ?Ya se ha dicho que la
extern
palabra clave es redundante para las funciones.En cuanto a las variables compartidas entre las unidades de compilación, debe declararlas en un archivo de encabezado con la palabra clave externa, luego definirlas en un único archivo fuente, sin la palabra clave externa. El archivo de origen único debe ser el que comparte el nombre del archivo de encabezado, para la mejor práctica.
fuente
Muchos años después, descubro esta pregunta. Después de leer cada respuesta y comentario, pensé que podría aclarar algunos detalles ... Esto podría ser útil para las personas que llegan aquí a través de la búsqueda de Google.
La pregunta es específicamente sobre el uso de funciones "externas", por lo que ignoraré el uso de "externas" con variables globales.
Definamos 3 prototipos de funciones:
El archivo de encabezado puede ser utilizado por el código fuente principal de la siguiente manera:
Para compilar y vincular, debemos definir "function_2" en el mismo archivo de código fuente donde llamamos a esa función. Las otras dos funciones se pueden definir en un código fuente diferente " .C" o se pueden ubicar en cualquier archivo binario ( .OBJ, * .LIB, * .DLL), para el cual es posible que no tengamos el código fuente.
Incluyamos nuevamente el encabezado "my_project.H" en un archivo "* .C" diferente para comprender mejor la diferencia. En el mismo proyecto, agregamos el siguiente archivo:
Características importantes a tener en cuenta:
Cuando una función se define como "estática" en un archivo de encabezado, el compilador / vinculador debe encontrar una instancia de una función con ese nombre en cada módulo que utiliza ese archivo de inclusión.
Una función que forma parte de la biblioteca C puede reemplazarse en un solo módulo redefiniendo un prototipo con "estático" solo en ese módulo. Por ejemplo, reemplace cualquier llamada a "malloc" y "gratis" para agregar la función de detección de pérdida de memoria.
El especificador "extern" no es realmente necesario para las funciones. Cuando no se encuentra "estático", siempre se supone que una función es "externa".
Sin embargo, "extern" no es el valor predeterminado para las variables. Normalmente, cualquier archivo de encabezado que defina variables para que sean visibles en muchos módulos debe usar "extern". La única excepción sería si se garantiza que un archivo de encabezado se incluya desde un solo módulo.
Muchos administradores de proyectos requerirían que dicha variable se coloque al comienzo del módulo, no dentro de ningún archivo de encabezado. Algunos proyectos grandes, como el emulador de videojuegos "Mame", incluso requieren que dicha variable aparezca solo por encima de la primera función que los usa.
fuente
En C, 'extern' está implícito para los prototipos de funciones, ya que un prototipo declara una función que se define en otro lugar. En otras palabras, un prototipo de función tiene un enlace externo por defecto; usar 'extern' está bien, pero es redundante.
(Si se requiere un enlace estático, la función debe declararse como 'estática' tanto en su prototipo como en el encabezado de la función, y estos normalmente deberían estar en el mismo archivo .c).
fuente
Un muy buen artículo sobre la
extern
palabra clave, junto con los ejemplos: http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/Aunque no estoy de acuerdo en que usar
extern
declaraciones en funciones sea redundante. Se supone que esta es una configuración del compilador. Por lo tanto, recomiendo usar lasextern
declaraciones en la función cuando sea necesario.fuente
Si cada archivo de su programa se compila primero en un archivo de objeto, entonces los archivos de objeto se vinculan entre sí, es necesario
extern
. Le dice al compilador "Esta función existe, pero su código está en otro lugar. No se asuste".fuente
Todas las declaraciones de funciones y variables en los archivos de encabezado deben ser
extern
.Las excepciones a esta regla son las funciones en línea definidas en el encabezado y las variables que, aunque definidas en el encabezado, tendrán que ser locales para la unidad de traducción (el archivo fuente en el que se incluye el encabezado): estas deberían ser
static
.En los archivos de origen,
extern
no debe usarse para funciones y variables definidas en el archivo. Simplemente prefije las definiciones locales constatic
y no haga nada para las definiciones compartidas: serán símbolos externos de forma predeterminada.La única razón para usar
extern
un archivo fuente es declarar funciones y variables que están definidas en otros archivos fuente y para las cuales no se proporciona ningún archivo de encabezado.Declarar prototipos de funciones
extern
es realmente innecesario. A algunas personas no les gusta porque solo desperdiciará espacio y las declaraciones de funciones ya tienden a desbordar los límites de la línea. A otros les gusta porque de esta manera, las funciones y las variables se pueden tratar de la misma manera.fuente
extern
es opcional para las declaraciones de funciones, pero me gusta tratar las variables y las funciones de la misma manera, al menos eso es lo más razonable que se me ocurre, ya que no recuerdo exactamente por qué comencé a hacer esto;)Las funciones realmente definidas en otros archivos fuente solo deben declararse en encabezados. En este caso, debe usar extern al declarar el prototipo en un encabezado.
La mayoría de las veces, sus funciones serán una de las siguientes (más como una mejor práctica):
fuente
Cuando tiene esa función definida en un dll o lib diferente, de modo que el compilador difiere al enlazador para encontrarlo. El caso típico es cuando está llamando a funciones desde la API del sistema operativo.
fuente