2010-07-30 7 views
18

Cuando declaro una función en un archivo de cabecera y pongo la definición de esa función en algún otro archivo, ¿cómo encuentra el compilador/vinculador la definición? ¿Busca sistemáticamente cada archivo en su camino, o hay una solución más elegante? Esto me ha estado molestando durante los últimos días, y no he podido encontrar una explicación para ello.¿Cómo encuentra un compilador C/C++ las definiciones de prototipos en archivos de encabezado?

+0

Gracias por hacer esta pregunta. Me preguntaba lo mismo. –

+1

Encontré esto realmente útil: http://www.lurklurk.org/linkers/linkers.html – letmaik

Respuesta

24

El compilador no hace esto, el enlazador sí.

Mientras el compilador trabaja en un archivo fuente a la vez, cuando se invoca el enlazador se pasan los nombres de todos los archivos de objeto generados por el compilador, así como las bibliotecas que el usuario desee vincular Por lo tanto, el vinculador tiene un conocimiento completo del conjunto de archivos que potencialmente podría contener la definición, y solo necesita mirar en las tablas de símbolos de esos archivos de objetos. No necesita hacer ninguna búsqueda más allá de eso.

Por ejemplo, supongamos que tiene foo.h y foo.c definiendo e implementando la función foo(), y bar.h y bar.c definiendo e implementando bar(). Diga bar llamadas foo para que bar.c incluya foo.h. Hay tres pasos para esta compilación:

gcc -c foo.c 
gcc -c bar.c 
gcc foo.o bar.o -o program 

La primera línea compila foo.c, produciendo foo.o. El segundo compila bar.c, produciendo bar.o. En este punto, en el archivo de objeto bar.o, foo es un símbolo externo. La tercera línea invoca al enlazador, que vincula foo.o y bar.o a un ejecutable llamado "programa". Cuando el enlazador procesa bar.o, ve el símbolo externo no resuelto foo y, por lo tanto, busca en la tabla de símbolos de todos los otros archivos objeto que están vinculados (en este caso solo foo.o) y encuentra foo en foo.o, y completa el enlace.

Con bibliotecas esto es un poco más complicado, y el orden en que aparecen en la línea de comandos puede importar dependiendo de su enlazador, pero generalmente es el mismo principio.

+7

Buena respuesta: vale la pena agregar que al menos una biblioteca, la biblioteca C estándar, está * implícitamente * incluida en la línea de enlace. Entonces, en este caso, se vería no solo en 'foo.o' sino también en la biblioteca C estándar para símbolos no resueltos. – caf

+2

* Y *, al enlazar con g ++ obtendrá -lstdC++ también de manera predeterminada. – Bklyn

14

Cuando compila un archivo .cpp, el compilador genera dos tablas en el archivo .obj: una lista de símbolos que espera que se defina externamente, así como una lista de símbolos que se definen en ese particular módulo.

El vinculador toma todos los archivos .obj que fueron generados por el compilador y luego (como su nombre indica) los vincula todos juntos. Entonces, para cada módulo, mira la lista de símbolos que están marcados como "definidos externamente" y mira a través de todos los otros módulos que se le dieron para esos símbolos.

Por lo tanto, sólo alguna vez "búsquedas" los módulos que le dijo que buscar.

Si no puede encontrar el símbolo en cualquiera de los otros módulos, que es cuando se obtiene el error "referencia indefinida".

+0

Ahora sé en qué caso me aparece el error de "referencia no definida". Quiero decir que el compilador (más precisamente el vinculador) no puede encontrar el símbolo externo no resuelto que se espera que se defina en otros módulos. –

0

Supongamos que tiene un foo.cpp con un #include foo.h y tal vez otro incluye. Los encabezados pueden tener sus propios #incluidos-s.

El preprocesador comenzará con foo.cpp, analizará los #includes y leerá el contenido del encabezado. El resultado será texto de los archivos de encabezado y foo.cpp "aplanado". El compilador trabajará con ese texto. Si una variable/función/etc. debería tener declarado en alguna parte en un encabezado no se encontró, el compilador informará un error.

El punto básico es que el compilador tiene que ver todas sus declaraciones como resultado de .cpp y los encabezados.

Cuestiones relacionadas