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?
Respuesta
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.
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
* Y *, al enlazar con g ++ obtendrá -lstdC++ también de manera predeterminada. – Bklyn
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".
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. –
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.
- 1. Cómo generar definiciones vacías dado un archivo de encabezado
- 2. ¿Cómo encuentra un compilador de C que -lm apunta al archivo libm.a?
- 3. poniendo definiciones de funciones en los archivos de cabecera
- 4. ¿Cómo compilar y vincular archivos de objeto en C++ usando el mismo archivo de encabezado?
- 5. ¿Cómo prefiere organizar las definiciones de excepción?
- 6. Cuándo usar archivos de encabezado que no declaran una clase pero tienen definiciones de función
- 7. ¿Compila un C++ .lib con solo archivos de encabezado?
- 8. ¿Qué significa CC? = En un Makefile?
- 9. Cómo usar archivos de encabezado precompilados en Android NDK
- 10. El comportamiento de un compilador C con funciones de estilo antiguo y sin prototipos
- 11. objetos no heredan las funciones de prototipos
- 12. cómo vincular archivos de encabezado en C++
- 13. Propósito de C/C Prototipos ++
- 14. ¿Cómo se evalúan las definiciones de macros recursivas
- 15. ¿Cómo funcionan los archivos de encabezado y fuente en C?
- 16. Definición de la variable en archivos de encabezado
- 17. dificultades con "cl.exe" (compilador de línea de comandos de VisualStudio) y archivos de encabezado!
- 18. Detalles de call/cc
- 19. Encabezados precompilados en archivos de encabezado
- 20. Evitando las dependencias circulares de los archivos de encabezado
- 21. ¿Cómo incluir archivos de encabezado en Visual Studio 2008?
- 22. Las variables locales en las definiciones de clase/ámbito
- 23. Cómo puedo crear archivos de encabezado C
- 24. C Archivos de encabezado - Forma correcta de incluir
- 25. En makefiles, ¿qué significan CC y LD?
- 26. ¿Cómo declaras las matrices en un encabezado C++?
- 27. ¿Cómo cambian DP y CC en Piet?
- 28. Archivos de encabezado no encontrados
- 29. ¿Cómo puedo fusionar las definiciones de CSS en archivos en atributos de estilo en línea, usando Perl?
- 30. ¿Cómo obtener todas las definiciones en un ApplicationDomain de un SWF cargado?
Gracias por hacer esta pregunta. Me preguntaba lo mismo. –
Encontré esto realmente útil: http://www.lurklurk.org/linkers/linkers.html – letmaik