En tiempo de compilación, el compilador exporta cada símbolo global al ensamblador como fuerte o débil, y el ensamblador codifica esta información implícitamente en la tabla de símbolos del archivo de objetos reubicables. Las funciones y las variables globales inicializadas obtienen símbolos fuertes. Las variables globales no inicializadas obtienen símbolos débiles. Para los siguientes programas de ejemplo, buf, bufp0, main y swap son símbolos fuertes; bufp1 es un símbolo débil.
C
/* main.c */ void swap(); int buf[2] = {1, 2}; int main() { swap(); return 0; } /* swap.c */ extern int buf[]; int *bufp0 = &buf[0]; int *bufp1; void swap() { int temp; bufp1 = &buf[1]; temp = *bufp0; *bufp0 = *bufp1; *bufp1 = temp; }
Dada esta noción de símbolos fuertes y débiles, los enlazadores de Unix usan las siguientes reglas para manejar múltiples símbolos definidos: Regla 1: No se permiten múltiples símbolos fuertes (con el mismo nombre de variable). Regla 2: dado un símbolo fuerte y múltiples símbolos débiles, elija el símbolo fuerte. Regla 3: dados múltiples símbolos débiles, elija cualquiera de los símbolos débiles. Por ejemplo, supongamos que intentamos compilar y vincular los siguientes dos módulos C:
C
/* foo1.c */ int main() { return 0; } /* bar1.c */ int main() { return 0; }
En este caso, el enlazador generará un mensaje de error porque el símbolo fuerte principal se define varias veces ( regla 1 ):
$ gcc foo1.c bar1.c /tmp/cca015022.o: In function ‘main’: /tmp/cca015022.o(.text+0x0): multiple definition of ‘main’ /tmp/cca015021.o(.text+0x0): first defined here
De manera similar, el enlazador generará un mensaje de error para los siguientes módulos porque el símbolo fuerte x se define dos veces ( regla 1 ):
C
/* foo2.c */ int x = 15213; int main() { return 0; } /* bar2.c */ int x = 15213; void f() { }
Sin embargo, si x no está inicializado en un módulo, entonces el enlazador elegirá silenciosamente el símbolo fuerte definido en el otro ( regla 2 ), como es el caso en el siguiente programa:
C++
/* foo3.c */ #include <iostream> void f(void); int x = 15213; int main() { f(); std::cout << "x = " << x << std::endl; return 0; } /* bar3.c */ int x; void f() { x = 15212; }
C
/* foo3.c */ #include <stdio.h> void f(void); int x = 15213; int main() { f(); printf("x = %d\n", x); return 0; } /* bar3.c */ int x; void f() { x = 15212; }
En tiempo de ejecución, la función f() cambia el valor de x de 15213 a 15212, ¡lo que podría ser una sorpresa desagradable para el autor de la función principal! Tenga en cuenta que el enlazador normalmente no da ninguna indicación de que ha detectado múltiples definiciones de x.
$ gcc -o gfg foo3.c bar3.c $ ./gfg x = 15212
Lo mismo puede suceder si hay dos definiciones débiles de x ( regla 3 ):
C
/*a.c*/ #include <stdio.h> void b(void); int x; int main() { x = 2016; b(); printf("x = %d ",x); return 0; } /*b.c*/ #include <stdio.h> int x; void b() { x = 2017; }
La aplicación de las reglas 2 y 3 puede introducir algunos errores de tiempo de ejecución insidiosos que son incomprensibles para el programador incauto, especialmente si las definiciones de símbolos duplicados tienen diferentes tipos. Ejemplo: «x» se define como un int en un módulo y un doble en otro.
C
/*a.c*/ #include <stdio.h> void b(void); int x = 2016; int y = 2017; int main() { b(); printf("x = 0x%x y = 0x%x \n", x, y); return 0; } /*b.c*/ double x; void b() { x = -0.0; }
Ejecución:
$ gcc a.c b.c -o geeksforgeeks $ ./geeksforgeeks x = 0x0 y = 0x80000000
Este es un error sutil y desagradable, especialmente porque ocurre silenciosamente, sin advertencia del sistema de compilación, y porque normalmente se manifiesta mucho más tarde en la ejecución del programa, lejos de donde ocurrió el error. En un sistema grande con cientos de módulos, un error de este tipo es extremadamente difícil de corregir, especialmente porque muchos programadores no saben cómo funcionan los enlazadores. En caso de duda, invoque el enlazador con un indicador como el indicador gcc -fno-common, que desenstring un error si encuentra varios símbolos globales definidos. Fuente: http://csapp.cs.cmu.edu/public/ch7-preview.pdf Este artículo es una contribución de Sahil Rajput . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.orgo envíe su artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks. Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
Publicación traducida automáticamente
Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA