2010-04-08 15 views
34

Si he entendido bien esto significapalabra clave C++ extern en las funciones. ¿Por qué no solo incluir el archivo de encabezado?

extern void foo(); 

que la función foo se declara en otra unidad de traducción.

1) ¿Por qué no simplemente #incluye el encabezado en el que se declara esta función?

2) ¿Cómo sabe el vinculador dónde buscar la función en el tiempo de enlace?

edición: Tal vez debería aclarar que la declaración anterior es seguido por el uso de la función

foo(); 

Nunca se define en esta unidad de traducción.

Respuesta

26

1) Es posible que no tenga un archivo de encabezado. Pero sí, en general, para proyectos grandes, debe tener un archivo de cabecera si varias unidades de traducción van a usar esa función (no se repita).

2) El vinculador busca a través de todos los archivos de objeto y bibliotecas sobre las funciones y otros símbolos.

+0

¿Esto significa que puede llamar a las funciones internas de un módulo (supongamos que la fuente no está disponible) si conoce la firma de la función? – user199421

+1

Si las funciones tienen un enlace externo, entonces sí.Sin embargo, no podrá llamar a las funciones declaradas en un espacio de nombres sin nombre o declaradas estáticas (a menos que sepa cómo su compilador/enlazador descifra los nombres). –

2

1) No sé por qué necesitaría esto para una función. Tal vez alguien más pueda intervenir.

2) El enlazador determina esto pasando por todos los archivos de objeto y comprobando los símbolos dentro de cada archivo de objeto. Supongo que, dependiendo de su vinculador, el orden de búsqueda exacto puede variar.

Para GNU binutils 'ld todos los archivos de objetos y bibliotecas que aparecen en la línea de comando del enlazador después de que el objeto que contiene el símbolo faltante se buscan de izquierda a derecha y se selecciona el primer símbolo encontrado.

Ejemplo 1:

  • ao - utiliza foo(), bar()
  • Liba - ofrece bar()
  • libB - proporciona foo()

$> ld ao -la -lb

dará lugar a que se busquen símbolos indefinidos. A continuación, ld pasará por las bibliotecas de izquierda a derecha para buscar estos símbolos y encontrará barras en liba y foo en libb.

Esto puede conducir a problemas extraños sobre dependencias circulares:

Ejemplo 2:

  • a.O - utiliza bar()
  • Liba - proporciona bar(), utiliza foo()
  • libB - proporciona foo(), utiliza la barra()

Ahora, hay una dependencia circular entre Liba y libB y la vinculación fallará:

$> ld ao -la -lb

porque cuando se busca a través de los símbolos no definidos en libB, ld determinará que no hay otro lib a la derecha - lb que proporciona este símbolo. Esto puede ser fijado en por lo menos dos maneras:

1) Enlace Liba dos veces: $> ld ao -la -lb -la

2) Utiliza la función de agrupación de LD $> ld ao --start- group -la -lb --end-group

En el caso 2), la agrupación le dice a ld que busque a través de todos los símbolos en todas las libs que pertenecen a este grupo.

7

Ya significa que sin la palabra clave extern. Las funciones tienen un enlace externo por defecto, a menos que las declare estáticas.

El uso de prototipos de funciones está bien, pero es fácil equivocarse. El error del enlazador que obtendrá no es tan fácil de diagnosticar cuando redefine la implementación de la función. El vinculador no sabe dónde buscar, es su trabajo darle un archivo de objeto que contenga la definición de la función para mantenerlo feliz.

11

No, esto significa que la función foo se declara con el enlace externo . Enlace externo significa que el nombre foo se refiere a la misma función en todo el programa. Donde la función está definida no importa. Se puede definir en esta unidad de traducción. Se puede definir en otra unidad de traducción.

El uso de la palabra clave extern como se muestra en el ejemplo es superfluo. Las funciones siempre tienen un enlace externo por defecto. Lo anterior es 100% equivale a poco

void foo(); 

En cuanto al enlazador, cuando el enlazador enlaza el programa juntos, simplemente se ve en todas partes . Examina todas las definiciones hasta que encuentra la definición foo.

10

Como ya se ha mencionado, la palabra clave extern se usa para indicar que el nombre (una variable o función) tiene una vinculación externa, lo que significa que el nombre hace referencia al mismo objeto en todo el programa. Además, este es el valor predeterminado para las variables y funciones definidas en el alcance del archivo, por lo que este uso es superfluo.

Hay otro uso de la palabra clave extern que dice así:

extern "C" void foo(); 

Esto significa que la función foo se enlazará utilizando las convenciones C de vinculación (tal vez porque se trata de una función definida en una biblioteca C o es una función destinada a ser llamada por los programas C).

Cuestiones relacionadas