2010-07-30 16 views
9

Ich möchte wissen, was ist statische Block in C oder C++ mit einem Beispiel? Ich weiß, was ist statisch, aber was ist der Unterschied zwischen statischen und statischen Block?Was ist ein statischer Block in c oder C++?

+13

So etwas gibt es in keiner der beiden Sprachen. –

+1

überprüfen Sie Ihre Header für eine # define Block .... vielleicht jemand definiert "Block" ... – santa

+0

@Neil - Ich habe "statische" -Konzept durch Google-Suchmaschine und wenn ich "statischen Block" bei Google getippt , Ich fand eine Option, die besagt, dass "statische Block in c" – Abhineet

Antwort

28

Eine andere Alternative ist, dass Sie vielleicht nach der Analogie eines statischen Blocks in Java suchen. Ein Codeblock, der beim Laden der Anwendung ausgeführt wird. Es gibt keine solche Sache in C++, aber es kann gefälscht werden, indem Sie den Konstruktor eines statischen Objekts verwenden.

foo.cpp: 

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


static StaticBlock staticBlock; 

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

} 

JEDOCH. Ich bin schon vorher gebissen worden, da es ein subtiler Randfall des C++ Standards ist. Wenn das statische Objekt nicht mit einem von main aufgerufenen Code erreichbar ist, kann der Konstruktor des statischen Objekts aufgerufen werden oder nicht.

Ich habe festgestellt, dass mit gcc hallo wird ausgegeben und mit Visual Studio wird es nicht.

+3

+1: Auch die Reihenfolge der Initialisierung ist undefiniert, die auch alle Arten von Kopfschmerzen geben kann. Ich würde auch gerne ein zuverlässiges Statik-Initialisierungs-Framework sehen. –

+0

+1 für die Erwähnung möglicher nicht erreichbarer Fall. Bist du sicher, dass es nicht aufgerufen wird und nicht nur zur Kompilierzeit entfernt wird? Ich würde vermuten, dass sogar gcc dies mit genügend Optimierungsflags machen würde. – EntangledLoops

+1

@EntangledLoops: Nein, Sie können sicher sein, dass [wird nicht entfernt] (http://coliru.stacked-crooked.com/a/6af8f97e6f5f7610). Bradgonesurfing: Warum sollte man eine Klasse benutzen? Reicht es nicht aus, [static-initialize ein int mit einer Funktion] (http://stackoverflow.com/a/34321324/1593077)? – einpoklum

0

In C++ gibt es das Konzept eines anonymen Namespace.

foo.cpp: 

namespace { 
    int x; 
    int y; 
} 

den gleichen Effekt in C

foo.cpp: 

static int x; 
static int y; 

In einfachen Worten bekommen die Compiler keine Symbole aus Übersetzungseinheiten nicht exportieren, wenn sie entweder statisch oder in einem anonymen Namespace deklariert sind.

+0

Was bedeutet "Symbole exportieren"? Der C++ - Standard definiert diese Terminologie nicht. Es spricht jedoch von "Verknüpfung" und in Bezug auf die Verknüpfung ist Ihre Behauptung falsch, soweit ich das beurteilen kann. Diese beiden Beispiele haben nicht den gleichen Effekt. "x" und "y" aus dem anonymen Namespace haben eine externe Verknüpfung, während die anderen beiden eine interne Verknüpfung haben. Aber ich verstehe, was du meintest. Sie haben gemeint, dass andere Übersetzungseinheiten nicht auf diese Variablen nach Namen verweisen können. – sellibitze

+0

Elemente in anonymen Namespaces haben nur * interne Verknüpfung *. http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/unnamed_namespaces.htm gut, so sagt IBM. Hat jemand dazu einen Zeiger auf den C++ - Standard? – bradgonesurfing

+0

Ok. Ich habe eine Kopie des Standards aufgespürt und es sagt folgendes. "Obwohl Entitäten in einem unbenannten Namespace möglicherweise eine externe Verknüpfung haben, werden sie effektiv durch einen für ihre Übersetzungseinheit eindeutigen Namen qualifiziert." Ich vermute, dass dies in der Praxis compilerabhängig ist, aber der Effekt ist derselbe. – bradgonesurfing

5

In C/C++ gibt es kein Konzept mit dem Namen "statischer Block". Java hat es jedoch einen "statischen Block" ist ein Initialisierungscodeblock für eine Klasse, die genau einmal ausgeführt wird, bevor die erste Instanz einer Klasse erstellt wird. Das Grundkonzept ‚Sachen, die genau einmal laufen‘ in C/C++ mit einer statischen Variablen, zum Beispiel simuliert:

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; 
} 
... 
} 

Dies ist nicht Thread-sicher aber. Es kann manchmal schwierig und schwierig sein, dies bei mehreren Threads richtig zu machen.

15

Ich fand this Antwort auf The Code Project. Es beinhaltet eine zusätzliche statische Variable, aber ich glaube, es ist zuverlässiger als die Antwort von Bradgonesurfing. Im Grunde ist es das:

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(); 

Es bedeutet auch, dass, wie Java statische Blöcke, Sie sind nicht immer tatsächlich erforderlich ist, um eine Instanz von class Foo zu haben, was nützlich ist, wenn die Klasse eine Menge Daten nehmen, und Sie müssen einfach automatisch etwas aufrufen, bevor es geladen wird, und keine zusätzliche Instanz davon instanziieren. Sie können diesen genauen Codeblock testen. Ich habe es nur kompiliert (mit einer kleinen Ausgabe von static_init()) und hatte main() print Foo :: __ st_init, nur um sicher zu gehen, und es hat gut geklappt.

$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:

Sorry, dass es so spät ist, aber ich getestet, was bradgonesurfing erwähnt:

Wenn Sie es testen, meine in Haupt die Variable Zugriff auf „nur machen Sicher " Sie sicherstellen, dass die Variable erreichbar ist und somit die Variable initialisiert werden und damit static_init aufgerufen wird. Sind Sie sicher, dass es ausführt, wenn Sie drucken nicht Foo :: __ st_init

ich verwendet, um die folgende innen main.cpp:

#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; 
} 

ich mit g++ ./main.cpp -o main zusammengestellt und es lief und erhielt ein freundliches „Hallo, Welt!" Nachricht auf meiner Konsole. Nur um genau zu sein, kompilierte ich auch die gleiche Version, aber ohne den Druck und kompiliert mit g++ ./main.cpp -g -o main. Ich lief dann die ausführbare Datei mit GDB und hatte folgendes Ergebnis:

(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) 

Hier ist eine aktuellere Version Ausgabe für g ++: g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2

+2

Wenn Sie es testen meinen Zugriff auf die Variable in Main "nur um sicherzustellen," Sie sicherstellen, dass die Variable erreichbar ist und somit die Variable initialisiert wird und damit static_init aufgerufen wird. Bist du sicher, dass es ausgeführt wird, wenn du ** nicht ** druckst Foo :: __ st_init – bradgonesurfing

+0

Das ist ein toller Punkt, Bradgonesurfing. Ich habe meine Antwort mit ausreichenden Tests aktualisiert und es scheint trotzdem zu funktionieren. Entschuldige, dass du zwei Jahre zu spät bist, wenn du das jemals liest ... Ich weiß nicht, warum ich nie geantwortet habe. – Caleb1994

+1

Danke für einen Ansatz, der in einigen Fällen funktioniert, aber das funktioniert leider nicht, wenn Sie die statische Methode innerhalb einer separaten statischen Bibliothek aufrufen ... Selbst wenn Sie den Foo-Header in Ihre main.cpp einfügen. –

1

Während in der Tat, C++ nicht über statische Blöcke als Teil der Sprache, Sie kann implementieren statischen Blöcke, ohne dass Sie (als Benutzer) alle Klassen oder Namensraum zu verwenden, und schreiben:

#include "static_block.h" 

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

oder was auch immer Sie wollen. Sie können diese nicht innerhalb von Klassen haben, nur im Dateiumfang. Siehe eine detaillierte Beschreibung von diesen in meinem answer zu einer verwandten Frage, und der Code für static_block.hhere.

Hinweis: Dies erfordert nicht C++ 11 und funktioniert gut mit alten Compilern.

+0

Das ist eine interessante Lösung, aber es ist erwähnenswert, dass es mehr als den von Ihnen geposteten Code-Block gibt. Es gibt ein paar Makros, die definiert werden müssen und es benutzt C++ 11 Lambdas. Ich stimme zu, dass Ihre Lösung einen schlankeren (auch eleganten) Ansatz bietet. Es nutzt Features von C++ 11, mit denen ich damals nicht vertraut war. Meine Antwort wurde vor 4 Jahren geschrieben, als der C++ 11 Standard ziemlich neu war und noch nicht unbedingt Mainstream war. – Caleb1994

+0

@ Caleb1994: Eigentlich hat dieser Mechanismus nichts mit C++ 11 zu tun, es ist C++ 98 und vielleicht sogar früher. Keine Initialisierungslisten, Klassen, nichts Besonderes - nur einige Präprozessor-Builtins für eine eindeutige Kennung und die Tatsache, dass C++ statische Initialisierung hat. Wie auch immer, ich habe eine '# include'-Anweisung und einen Link zum Code hinzugefügt. – einpoklum

+0

Whoops, ich lese die falsche Antwort. Ja, es gibt keine Lust auf Ihre Lösung. Du hast recht. Obwohl die C++ 11-Lambdas-Lösung über Ihnen aussieht, sieht es ziemlich gut aus. Es kann innerhalb eines Funktionsbereichs verwendet werden (obwohl ich persönlich es nicht getestet habe). Ihre Lösung ist prozedural und würde sogar in C89 funktionieren, denke ich, haha. – Caleb1994