2010-07-30 12 views
9

Voglio sapere che cos'è un blocco statico in c o C++ con un esempio? So cosa è statico ma qual è la differenza tra blocco statico e blocco statico?Che cos'è un blocco statico in c o C++?

+13

Non esiste una cosa del genere, in nessuna delle due lingue. –

+1

controlla le intestazioni per un blocco #define .... forse qualcuno definito "blocco" ... – santa

+0

@Neil - Stavo esplorando il concetto "statico" tramite il motore di ricerca di Google e quando ho digitato "blocco statico" su google , ho trovato una opzione affermando che "blocco statico in c" – Abhineet

risposta

28

Un'altra alternativa è che si potrebbe cercare l'analogia di un blocco statico in Java. Un blocco di codice che viene eseguito quando viene caricata l'applicazione. Non c'è nulla di simile in C++ ma può essere simulato usando il costruttore di un oggetto statico .

foo.cpp: 

struct StaticBlock { 
    StaticBlock(){ 
     cout << "hello" << endl; 
    } 
} 


static StaticBlock staticBlock; 

void main(int, char * args[]){ 

} 

TUTTAVIA. Sono stato morso da questo prima perché si tratta di un sottile caso limite dello standard C++ . Se l'oggetto statico non è raggiungibile da alcun codice chiamato da main, il costruttore dell'oggetto statico può essere chiamato o meno.

Ho trovato che con gcc ciao verrà visualizzato l'output e con Visual Studio sarà non.

+3

+1: Inoltre, l'ordine di inizializzazione non è definito, il che può anche dare tutti i tipi di mal di testa. Mi piacerebbe vedere anche un affidabile framework di inizializzazione statica. –

+0

+1 per menzionare possibili casi non raggiungibili. Sei sicuro che non venga chiamato e non venga rimosso completamente al momento della compilazione? Sospetto che anche gcc lo farebbe con abbastanza bandiere di ottimizzazione. – EntangledLoops

+1

@EntangledLoops: No, puoi stare tranquillo [non viene rimosso] (http://coliru.stacked-crooked.com/a/6af8f97e6f5f7610). bradgonesurfing: perché preoccuparsi di usare una lezione? Non è sufficiente solo [inizializzazione statica di un int con una funzione] (http://stackoverflow.com/a/34321324/1593077)? – einpoklum

0

In C++ esiste il concetto di spazio dei nomi anonimo.

foo.cpp: 

namespace { 
    int x; 
    int y; 
} 

per ottenere lo stesso effetto in C

foo.cpp: 

static int x; 
static int y; 

In termini semplici il compilatore non esporta i simboli da unità di traduzione, quando sono entrambi dichiarati statico o in uno spazio dei nomi anonima.

+0

Cosa significa "esportare simboli"? Lo standard C++ non definisce questa terminologia. Tuttavia, parla di "linkage" e in termini di linkage la tua affermazione è errata per quanto posso dire. Questi due esempi non hanno lo stesso effetto. 'x' e' y' dallo spazio dei nomi anonimo hanno un collegamento esterno mentre gli altri due hanno un collegamento interno. Ma capisco cosa intendevi. Volevi dire che le altre unità di traduzione non possono riferirsi a queste variabili per nome. – sellibitze

+0

Gli articoli in spazi dei nomi anonimi hanno solo * collegamento interno *. http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/unnamed_namespaces.htm bene, così dice IBM. Qualcuno ha un puntatore allo standard C++ su questo? – bradgonesurfing

+0

Ok. Ho rintracciato una copia dello standard e dice quanto segue. "Sebbene le entità in uno spazio dei nomi senza nome possano avere un collegamento esterno, sono effettivamente qualificate con un nome univoco per la loro unità di traduzione" Sospetto che nella pratica dipenda dal compilatore ma l'effetto è lo stesso. – bradgonesurfing

5

Non esiste un concetto con il nome "blocco statico" in C/C++. Java ha tuttavia, un "blocco statico" è un blocco di codice inizializzatore per una classe che viene eseguita esattamente una volta, prima che venga creata la prima istanza di una classe. Il concetto 'roba che viene eseguito solo una volta' base può simulato in C/C++ con una variabile statica, ad esempio:

int some_function(int a, int b) 
{ 
static bool once=true; 
if (once) 
{ 
    // this code path runs only once in the program's lifetime 
    once=false; 
} 
... 
} 

Questo non è thread-safe tuttavia. Ottenere questo funzionamento corretto in presenza di più thread può essere talvolta difficile e complicato.

15

Ho trovato la risposta this su The Code Project. Implica avere una variabile statica extra, ma credo che sia più affidabile della risposta di bradgonesurfing. In sostanza, è questo:

class Foo 
{ 
public: 
    static int __st_init; 
private: 
    static int static_init(){ 
     /* do whatever is needed at static init time */ 
     return 42; 
    } 
}; 
int Foo::__st_init = Foo::static_init(); 

Ciò significa anche che, come blocchi statici di Java, non sono tenuti ad avere mai realmente un'istanza di class Foo, che è utile quando la classe può prendere un sacco di dati, e devi semplicemente chiamare automaticamente qualcosa prima che si carichi, non istanziare un'istanza aggiuntiva. Puoi testare quel codice esatto. L'ho appena compilato (con un piccolo output di static_init(), e ho stampato main() Foo :: __ st_init, solo per essere sicuro), e ha funzionato bene.

$g++ -v 

Using built-in specs. 
COLLECT_GCC=g++ 
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper 
Target: x86_64-linux-gnu 
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.1-9ubuntu3' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu 
Thread model: posix 
gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3) 

EDIT:

dispiace che sia così tardi, ma ho provato quello che bradgonesurfing menzionati:

Se si prova il mio accesso alla variabile principale "solo per fare " assicurati che la variabile sia raggiungibile e quindi la variabile sarà inizializzata e quindi verrà chiamato static_init. Sei sicuro che eseguito se non stampare Foo :: __ st_init

ho usato il seguente main.cpp interna:

#include <iostream> 

using namespace std; 

class Foo 
{ 
public: 
    static int __st_init; 
private: 
    static int static_init(){ 
     /* do whatever is needed at static init time */ 
     cout << "Hello, World!"; 
     return 42; 
    } 
}; 
int Foo::__st_init = Foo::static_init(); 

int main(int argc, char** argv) 
{ 
     return 0; 
} 

ho compilato con g++ ./main.cpp -o main e corse e ricevuto un amichevole "Ciao, Mondo!" messaggio sulla mia console. Giusto per essere accurato, ho anche compilato la stessa versione ma senza la stampa e compilato con g++ ./main.cpp -g -o main. Allora ho fatto funzionare l'eseguibile con gdb e ha avuto il seguente risultato:

(gdb) break Foo::static_init 
Breakpoint 1 at 0x400740: file ./main.cpp, line 12. 
(gdb) start 
Temporary breakpoint 2 at 0x4006d8: file ./main.cpp, line 19. 
Starting program: /home/caleb/Development/test/main-c++ 

Breakpoint 1, Foo::static_init() at ./main.cpp:12 
12    return 42; 
(gdb) 

Ecco una corrente di uscita versione più per g ++: g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2

+2

Se si verifica il mio accesso alla variabile in "solo per assicurarsi" si sta garantendo che la variabile sia raggiungibile e quindi la variabile verrà inizializzata e quindi verrà chiamato static_init. Sei sicuro che venga eseguito se tu ** non ** stampi Foo :: __ st_init – bradgonesurfing

+0

Questo è un ottimo punto, bradgonesurfing. Ho aggiornato la mia risposta con test sufficienti e sembra funzionare comunque. Scusa due anni di ritardo, se mai hai letto questo ... non so perché non ho mai risposto. – Caleb1994

+1

Grazie per un approccio che funziona in alcuni casi, ma, sfortunatamente, questo non funziona se chiami il metodo statico all'interno, diciamo, in una libreria statica separata ... Anche se includi l'intestazione Foo nel tuo main.cpp. –

1

Mentre infatti, C++ non dispone blocchi statici come parte del linguaggio, è può implementare blocchi statici senza di te (come utente) dover utilizzare tutte le classi o gli spazi dei nomi, e in grado di scrivere:

#include "static_block.h" 

static_block { 
    int x = 1; 
    int y = 2; 
    int z = x+y; 
    std::cout << z << " = " << x " << " + " << y << "\n"; 
} 

o qualsiasi altra cosa che si desidera. Non è possibile avere quelli all'interno delle classi, però, solo nell'ambito del file. Vedere una descrizione dettagliata di questi nel mio answer a una domanda correlata e il codice per static_block.hhere.

Nota: Questo non richiede C++ 11 e funzionerà correttamente con i vecchi compilatori.

+0

Questa è una soluzione interessante, ma vale la pena ricordare che c'è di più ad esso il blocco di codice che hai postato. Ci sono alcune macro da definire e usa C++ 11 lambda. Sono d'accordo sul fatto che la tua soluzione offra un approccio più snello (anche elegante). Usa le caratteristiche di C++ 11 che non ero al momento familiare. La mia risposta è stata scritta 4 anni fa, quando lo standard C++ 11 era abbastanza nuovo e non necessariamente lo stream principale. – Caleb1994

+0

@ Caleb1994: In realtà, questo meccanismo non ha nulla a che fare con C++ 11, è C++ 98 e forse anche prima. Non usa liste di inizializzazione, classi, niente di speciale - solo alcuni builtin del preprocessore per un identificatore univoco, e il fatto che C++ abbia un'inizializzazione statica. Ad ogni modo, ho incluso una dichiarazione "# include" e un link al codice. – einpoklum

+0

Whoops, ho letto la risposta sbagliata. Sì, non c'è fantasia sulla soluzione. Hai ragione. Anche se la soluzione lambda di C++ 11 sopra la tua sembra piuttosto carina. Può essere utilizzato nell'ambito di una funzione (anche se personalmente non l'ho testato). La tua soluzione è procedurale e funzionerebbe anche in C89, penso, haha. – Caleb1994