Esempio di ambito multi-file eseguibile minimo
Qui illustrerò come static
influenza l'ambito delle definizioni delle funzioni su più file.
AC
#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();
}
main.c
#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 a monte .
Compila ed esegui:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
./main
Produzione:
main f
main sf
main f
a sf
Interpretazione
- ci sono due funzioni separate
sf
, una per ogni file
- c'è una singola funzione condivisa
f
Come al solito, minore è l'ambito, meglio è, quindi static
puoi sempre dichiarare le funzioni se puoi.
Nella programmazione C, i file vengono spesso utilizzati per rappresentare "classi" e le static
funzioni rappresentano metodi "privati" della classe.
Un modello C comune è quello di passare una this
struttura come primo argomento "metodo", che è fondamentalmente ciò che fa C ++ sotto il cofano.
Cosa dicono gli standard al riguardo
Bozza C99 N1256 6.7.1 " Identificatori della classe di archiviazione" indica che si static
tratta di un " identificatore della classe di archiviazione".
6.2.2 / 3 "Collegamenti di identificatori" dice static
implica internal linkage
:
Se la dichiarazione di un identificatore di ambito di file per un oggetto o una funzione contiene l'identificatore di classe di archiviazione statico, l'identificatore ha un collegamento interno.
e 6.2.2 / 2 dice che internal linkage
si comporta come nel nostro esempio:
Nell'insieme di unità di traduzione e librerie che costituisce un intero programma, ogni dichiarazione di un particolare identificatore con collegamento esterno indica lo stesso oggetto o funzione. All'interno di un'unità di traduzione, ogni dichiarazione di un identificatore con collegamento interno indica lo stesso oggetto o funzione.
dove "unità di traduzione" è un file sorgente dopo la preelaborazione.
In che modo GCC lo implementa per ELF (Linux)?
Con la STB_LOCAL
rilegatura.
Se compiliamo:
int f() { return 0; }
static int sf() { return 0; }
e disassemblare la tabella dei simboli con:
readelf -s main.o
l'output 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
quindi l'associazione è l'unica differenza significativa tra di loro. Value
è solo il loro offset nella .bss
sezione, quindi ci aspettiamo che differisca.
STB_LOCAL
è documentato sulle specifiche ELF all'indirizzo http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :
STB_LOCAL I simboli locali non sono visibili all'esterno del file oggetto che contiene la loro definizione. Simboli locali con lo stesso nome possono esistere in più file senza interferire tra loro
che lo rende una scelta perfetta da rappresentare static
.
Le funzioni senza elettricità statica sono STB_GLOBAL
e la specifica dice:
Quando l'editor di collegamenti combina diversi file di oggetti trasferibili, non consente più definizioni di simboli STB_GLOBAL con lo stesso nome.
che è coerente con gli errori di collegamento su più definizioni non statiche.
Se ottimizziamo l'ottimizzazione con -O3
, il sf
simbolo viene rimosso completamente dalla tabella dei simboli: non può comunque essere utilizzato dall'esterno. TODO perché mantenere le funzioni statiche sulla tabella dei simboli quando non c'è ottimizzazione? Possono essere usati per qualsiasi cosa?
Guarda anche
Spazi dei nomi anonimi C ++
In C ++, potresti voler usare spazi dei nomi anonimi anziché statici, il che ottiene un effetto simile, ma nasconde ulteriormente le definizioni dei tipi: spazi dei nomi senza nome / anonimi rispetto alle funzioni statiche