2010-07-30 6 views
9

Je veux savoir ce qu'est un bloc statique en c ou C++ avec un exemple? Je sais ce qui est statique mais quelle est la différence entre un bloc statique et statique?Qu'est-ce qu'un bloc statique en c ou C++?

+13

Il n'y a rien de tel, dans les deux langues. –

+1

vérifier vos en-têtes pour un #define #define .... peut-être quelqu'un défini "bloc" ... – santa

+0

@Neil - J'explorais concept "statique" par google moteur de recherche et quand j'ai tapé "bloc statique" à la google , j'ai trouvé une option indiquant que "bloc statique en c" – Abhineet

Répondre

28

Une autre alternative est que vous cherchiez peut-être l'analogie d'un bloc statique en Java. Un bloc de code qui est exécuté lorsque l'application est chargée. Il n'existe rien de tel en C++ mais il peut être truqué en utilisant le constructeur d'un objet statique .

foo.cpp: 

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


static StaticBlock staticBlock; 

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

} 

CEPENDANT. J'ai été mordu par cela avant car c'est un cas subtil de la norme C++ . Si l'objet statique n'est pas accessible par un code appelé par le principal, le constructeur de l'objet statique peut ou non être appelé.

J'ai trouvé qu'avec gcc hello obtiendra la sortie et avec le studio visuel ce sera pas.

+3

+1: De plus, l'ordre d'initialisation est indéfini, ce qui peut aussi donner toutes sortes de maux de tête. J'aimerais voir un cadre d'initialisation statique fiable aussi. –

+0

+1 pour mentionner un éventuel cas non accessible. Êtes-vous sûr que ce n'est pas appelé et pas simplement être enlevé à la compilation tout à fait? Je suppose que même gcc ferait cela avec suffisamment de drapeaux d'optimisation. – EntangledLoops

+1

@EntangledLoops: Non, vous pouvez être assuré que [n'est pas supprimé] (http://coliru.stacked-crooked.com/a/6af8f97e6f5f7610). bradgonesurfing: Pourquoi s'embêter à utiliser une classe? N'est-il pas suffisant de simplement [static-initialize un int avec une fonction] (http://stackoverflow.com/a/34321324/1593077)? – einpoklum

0

En C++, il y a le concept d'un espace de noms anonyme.

foo.cpp: 

namespace { 
    int x; 
    int y; 
} 

pour obtenir le même effet en C

foo.cpp: 

static int x; 
static int y; 

En termes simples, le compilateur n'exporte pas des symboles de unités de traduction quand ils sont soit déclarés statiques ou dans un espace de noms anonyme.

+0

Que signifie «exporter des symboles»? La norme C++ ne définit pas cette terminologie. Cependant, il parle de «lien» et en termes de lien votre réclamation est fausse autant que je peux dire. Ces deux exemples n'ont pas le même effet. 'x' et' y' de l'espace de noms anonyme ont un lien externe tandis que les deux autres ont un lien interne. Mais je comprends ce que tu voulais dire. Vous vouliez dire que les autres unités de traduction ne peuvent pas se référer à ces variables par leur nom. – sellibitze

+0

Les éléments des espaces de noms anonymes ont uniquement un * lien interne *. http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/unnamed_namespaces.htm bien, dit IBM. Est-ce que quelqu'un a un pointeur sur la norme C++? – bradgonesurfing

+0

Ok. J'ai retrouvé une copie de la norme et il est dit ce qui suit. "Bien que les entités dans un espace de nommage sans nom puissent avoir un lien externe, elles sont qualifiées par un nom propre à leur unité de traduction" Je suppose qu'en pratique, cela dépendra du compilateur mais l'effet est le même. – bradgonesurfing

5

Il n'y a pas de concept avec le nom "bloc statique" en C/C++. Java l'a cependant, un "bloc statique" est un bloc de code d'initialisation pour une classe qui s'exécute exactement une fois, avant que la première instance d'une classe soit créée. Le 'truc qui fonctionne exactement une fois' concept de base peut simuler en C/C++ avec une variable statique, par exemple:

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

Ceci est thread-safe cependant pas. Bien fonctionner en présence de plusieurs threads peut être difficile et délicat parfois.

15

J'ai trouvé this réponse sur The Code Project. Cela implique d'avoir une variable statique supplémentaire, mais je crois que c'est plus fiable que la réponse de bradgonesurfing. Au fond, il est ceci:

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

Cela signifie aussi que, comme des blocs statiques de Java, vous n'êtes pas obligé d'avoir jamais fait une instance de class Foo, ce qui est utile lorsque la classe peut prendre beaucoup de données, et Il suffit d'appeler automagiquement quelque chose avant de le charger, sans instancier une instance supplémentaire. Vous pouvez tester ce bloc de code exact. Je l'ai juste compilé (avec une petite sortie de static_init(), et ai eu main() print Foo :: __ st_init, juste pour être sûr), et ça a très bien fonctionné.

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

Désolé que ce soit si tard, mais j'ai testé ce bradgonesurfing mentionné:

Si vous testez mon accès à la variable principale « juste pour faire Bien sûr, " vous vous assurez que la variable est accessible et donc la variable sera initialisée et ainsi static_init sera appelée. Etes-vous sûr qu'il exécute si vous n'imprimer Foo :: __ st_init

je l'intérieur main.cpp suivant:

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

Je compilé avec g++ ./main.cpp -o main et couru et avons reçu un match amical « Bonjour, Monde!" message sur ma console. Juste pour être complet, j'ai également compilé la même version mais sans l'impression et compilé avec g++ ./main.cpp -g -o main. Je puis a couru l'exécutable avec gdb et a le résultat suivant:

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

Voici une sortie de version plus récente pour g ++: g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2

+2

Si vous le tester en accédant à la variable dans le champ principal "juste pour être sûr", vous vous assurez que la variable est accessible et donc la variable sera initialisée et donc static_init sera appelée. Êtes-vous sûr qu'il s'exécute si vous ** ne ** imprimez pas Foo :: __ st_init – bradgonesurfing

+0

C'est un excellent point, bradgonesurfing. J'ai mis à jour ma réponse avec suffisamment de tests et cela semble fonctionner de toute façon. Désolé d'avoir deux ans de retard, si jamais vous lisez ceci ... Je ne sais pas pourquoi je n'ai jamais répondu. – Caleb1994

+1

Merci pour une approche qui fonctionne dans certains cas, mais, malheureusement, cela ne fonctionne pas si vous appelez la méthode statique dans, disons, une bibliothèque statique séparée ... Même si vous incluez l'en-tête Foo dans votre main.cpp. –

1

Alors en effet, C++ ne dispose pas de blocs statiques dans le cadre de la langue, vous peut mettre en œuvre des blocs statiques sans vous (en tant qu'utilisateur) avoir à utiliser des classes ou des espaces de noms, et peut écrire:

#include "static_block.h" 

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

ou tout ce que vous voulez. Vous ne pouvez pas les avoir dans les classes, cependant, juste au niveau de la portée du fichier. Voir une description détaillée de ceux-ci dans mon answer à une question connexe, et le code pour static_block.hhere.

Remarque: Cela ne nécessite pas C++ 11 et fonctionnera bien avec les anciens compilateurs.

+0

C'est une solution intéressante, mais il vaut la peine de mentionner qu'il y a plus que le bloc de code que vous avez posté. Il y a quelques macros à définir et il utilise C++ 11 lambdas. Je suis d'accord que votre solution fournit une approche plus simple (aussi élégante). Il utilise des fonctionnalités de C++ 11 que je ne connaissais pas à l'époque. Ma réponse a été écrite il y a 4 ans quand le standard C++ 11 était assez récent et pas nécessairement le flux principal pour le moment. – Caleb1994

+0

@ Caleb1994: En fait, ce mécanisme n'a rien à voir avec C++ 11, c'est C++ 98 et peut-être même plus tôt. N'utilise pas les listes d'initialisation, les classes, rien de sophistiqué - juste quelques builtins préprocesseur pour un identifiant unique, et le fait que C++ possède une initialisation statique. Quoi qu'il en soit, j'ai inclus une instruction '# include 'et un lien vers le code. – einpoklum

+0

Oups, j'ai lu la mauvaise réponse. Oui, il n'y a pas de fantaisie sur votre solution. Tu as raison. Bien, la solution de C++ 11 lambdas au-dessus de la vôtre semble plutôt agréable. Il peut être utilisé dans une portée de fonction (bien que personnellement je ne l'ai pas testé). Votre solution est procédurale et pourrait même fonctionner en C89, je pense, haha. – Caleb1994