Ejemplo mínimo de alcance de múltiples archivos ejecutable
Aquí ilustramos cómo static
afecta el alcance de las definiciones de funciones en múltiples archivos.
C.A
#include <stdio.h>
/* Undefined behavior: already defined in main.
* Binutils 2.24 gives an error and refuses to link.
* /programming/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*void f() { puts("a f"); }*/
/* OK: only declared, not defined. Will use the one in main. */
void f(void);
/* OK: only visible to this file. */
static void sf() { puts("a sf"); }
void a() {
f();
sf();
}
C Principal
#include <stdio.h>
void a(void);
void f() { puts("main f"); }
static void sf() { puts("main sf"); }
void m() {
f();
sf();
}
int main() {
m();
a();
return 0;
}
GitHub aguas arriba .
Compilar y ejecutar:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
./main
Salida:
main f
main sf
main f
a sf
Interpretación
- Hay dos funciones separadas
sf
, una para cada archivo
- hay una sola función compartida
f
Como de costumbre, cuanto menor sea el alcance, mejor, así que siempre declare funciones static
si puede.
En la programación en C, los archivos se usan a menudo para representar "clases", y las static
funciones representan métodos "privados" de la clase.
Un patrón común de C es pasar una this
estructura como el primer argumento de "método", que es básicamente lo que C ++ hace bajo el capó.
¿Qué dicen las normas al respecto?
C99 N1256 draft 6.7.1 "Especificadores de clase de almacenamiento" dice que static
es un "especificador de clase de almacenamiento".
6.2.2 / 3 "Vínculos de identificadores" dice static
implica internal linkage
:
Si la declaración de un identificador de alcance de archivo para un objeto o una función contiene el especificador de clase de almacenamiento estático, el identificador tiene un enlace interno.
y 6.2.2 / 2 dice que se internal linkage
comporta como en nuestro ejemplo:
En el conjunto de unidades de traducción y bibliotecas que constituyen un programa completo, cada declaración de un identificador particular con enlace externo denota el mismo objeto o función. Dentro de una unidad de traducción, cada declaración de un identificador con enlace interno denota el mismo objeto o función.
donde "unidad de traducción" es un archivo fuente después del preprocesamiento.
¿Cómo lo implementa GCC para ELF (Linux)?
Con la STB_LOCAL
encuadernación.
Si compilamos:
int f() { return 0; }
static int sf() { return 0; }
y desmonte la tabla de símbolos con:
readelf -s main.o
la salida contiene:
Num: Value Size Type Bind Vis Ndx Name
5: 000000000000000b 11 FUNC LOCAL DEFAULT 1 sf
9: 0000000000000000 11 FUNC GLOBAL DEFAULT 1 f
entonces el enlace es la única diferencia significativa entre ellos. Value
es solo su desplazamiento en la .bss
sección, por lo que esperamos que sea diferente.
STB_LOCAL
está documentado en la especificación ELF en http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :
STB_LOCAL Los símbolos locales no son visibles fuera del archivo de objeto que contiene su definición. Los símbolos locales del mismo nombre pueden existir en varios archivos sin interferir entre sí
lo que lo convierte en una opción perfecta para representar static
.
Las funciones sin estática son STB_GLOBAL
, y la especificación dice:
Cuando el editor de enlaces combina varios archivos de objetos reubicables, no permite múltiples definiciones de símbolos STB_GLOBAL con el mismo nombre.
que es coherente con los errores de enlace en múltiples definiciones no estáticas.
Si aumentamos la optimización con -O3
, el sf
símbolo se elimina por completo de la tabla de símbolos: de todos modos, no se puede usar desde afuera. TODO, ¿por qué mantener las funciones estáticas en la tabla de símbolos cuando no hay optimización? ¿Se pueden usar para algo?
Ver también
Espacios de nombres anónimos C ++
En C ++, es posible que desee utilizar espacios de nombres anónimos en lugar de estáticos, lo que logra un efecto similar, pero oculta aún más las definiciones de tipo: espacios de nombres anónimos / sin nombre frente a funciones estáticas