10

I want to know that what is static block in c or c++ with an example? I know what is static but what is the difference between static and static block?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Abhineet
  • 6,459
  • 10
  • 35
  • 53

5 Answers5

31

Another alternative is that you might be looking for the analogy of a static block in Java. A block of code that is run when the application is loaded. There is no such thing in C++ but it can be faked by using the constructor of a static object.

foo.cpp:

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


static StaticBlock staticBlock;

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

}

HOWEVER. I've been bitten by this before as it's a subtle edge case of the C++ standard. If the static object is not reachable by any code called by main the constructor of the static object may or may not be called.

I found that with gcc hello will get output and with visual studio it will not.

bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217
  • 4
    +1: Also, the initialization order is undefined, which also can give all kinds of headaches. I'd like to see a reliable static-initialization framework too. – Nordic Mainframe Jul 30 '10 at 09:21
  • +1 for mentioning possible non-reachable case. Are you sure it's not being called and not just being removed at compile-time altogether? I would suspect even gcc would do this with enough optimization flags. – EntangledLoops May 11 '16 at 17:54
  • 1
    @EntangledLoops: No, you can rest assured it [is not being removed](http://coliru.stacked-crooked.com/a/6af8f97e6f5f7610). bradgonesurfing: Why bother using a class? Isn't it enough to just [static-initialize an int with with a function](http://stackoverflow.com/a/34321324/1593077)? – einpoklum Sep 02 '16 at 18:20
16

I found this answer on The Code Project. It involves having an extra static variable, but I believe it is more reliable than bradgonesurfing's answer. Basically, it is this:

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

It also means that, like Java's static blocks, you are not required to ever actually have an instance of class Foo, which is useful when the class can take a lot of data, and you simply need to automagically call something before it loads, not instantiate an extra instance of it. You can test that exact code block. I just compiled it (with a little output from static_init(), and had main() print Foo::__st_init, just to make sure), and it worked just fine.

$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 that this is so late, but I tested what bradgonesurfing mentioned:

If you test it my accessing the variable in main "just to make sure" you are ensuring the variable is reachable and thus the variable will be initialized and thus static_init will be called. Are you sure it executes if you dont print Foo::__st_init

I used the following inside 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;
}

I compiled with g++ ./main.cpp -o main and ran it and recieved a friendly "Hello, World!" message on my console. Just to be thorough, I also compiled the same version but without the printing and compiled with g++ ./main.cpp -g -o main. I then ran the executable with gdb and had the following result:

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

Here's a more current version output for g++: g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2

Community
  • 1
  • 1
Caleb Stewart
  • 643
  • 6
  • 21
  • 2
    If you test it my accessing the variable in main "just to make sure" you are ensuring the variable is reachable and thus the variable will be initialized and thus static_init will be called. Are you sure it executes if you **dont** print Foo::__st_init – bradgonesurfing Oct 23 '12 at 07:40
  • That's a great point, bradgonesurfing. I've updated my answer with sufficient tests and it appears to work anyway. Sorry for being two years late, if you ever read this... I don't know why I never replied. – Caleb Stewart Jun 01 '14 at 03:25
  • 1
    Thanks for an approach that works in some cases, but, unfortunately, this doesn't work if you call the static method within, say, a separate static library... Even if you include the Foo header in your main.cpp. – Greg Kramida Feb 26 '15 at 16:41
  • Caleb445: Don't you think that's kind of a lot of hassle? I mean, even with this same approach, you could/should macroify it so that it's less verbose to use. – einpoklum Sep 02 '16 at 18:14
5

There is no concept with the name "static block" in C/C++. Java has it however, a "static block" is an initializer code block for a class which runs exactly once, before the first instance of a class is created. The basic concept 'stuff that runs exactly once' can simulated in C/C++ with a static variable, for example:

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

This is not thread-safe however. Getting this working right in the presence of multiple threads can be difficult and tricky sometimes.

Nordic Mainframe
  • 28,058
  • 10
  • 66
  • 83
1

In C++ there is the concept of an anonymous namespace.

foo.cpp:

namespace {
    int x;
    int y;
}

to get the same effect in C

foo.cpp:

static int x;
static int y;

In simple terms the compiler does not export symbols from translation units when they are either declared static or in an anonymous namespace.

bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217
  • What does it mean to "export symbols" ? The C++ standard doesn't define this terminology. However, it speaks of "linkage" and in terms of linkage your claim is wrong as far as I can tell. These two examples don't have the same effect. `x` and `y` from the anonymous namespace have external linkage while the other two have internal linkage. But I do understand what you meant. You meant that other translation units cannot refer to these variables by name. – sellibitze Jul 30 '10 at 09:19
  • Items in anonymous namespaces have *internal linkage* only. http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/unnamed_namespaces.htm well, so says IBM. Does anyone have a pointer to the C++ standard on this? – bradgonesurfing Jul 30 '10 at 09:26
  • Ok. I tracked down a copy of the standard and it says the following. "Although entities in an unnamed namespace might have external linkage, they are effectively qualified by a name unique to their translation unit" I suspect in practice it will be compiler dependent but the effect is the same. – bradgonesurfing Jul 30 '10 at 09:31
1

While indeed, C++ does not have static blocks as part of the language, you can implement static blocks without you (as a user) having to use any classes or namespaces, and can write:

#include "static_block.h" 

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

or whatever else you want. You can't have those within classes, though, just at file scope. See a detailed description of these in my answer to a related question, and the code for static_block.h here.

Note: This does not require C++11 and will work well with old compilers.

Community
  • 1
  • 1
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • That is an interesting solution, but it's worth mentioning that there is more to it then the code block you posted. There's a few macros to be defined and it uses C++11 lambdas. I agree that your solution provides a more streamlined (also elegant) approach. It uses features of C++11 that I was not at the time familiar with. My answer was written 4 years ago when the C++11 standard was fairly new and not necessarily main stream yet. – Caleb Stewart Sep 02 '16 at 18:23
  • @Caleb1994: Actually, this mechanism has nothing to do with C++11, it's C++98 and maybe even earlier. Doesn't use initializer lists, classes, nothing fancy - just some preprocessor builtins for a unique identifier, and the fact that C++ has static initialization. Anyway, I included an `#include` statement and a link to the code. – einpoklum Sep 02 '16 at 18:30
  • Whoops, I read the wrong answer. Yes, there is no fancy-ness going on on your solution. You're right. Although, the C++11 lambdas solution above yours looks rather nice. It can be used within a function scope (although I personally haven't tested it). Your solution is procedural and would even work in C89 I think, haha. – Caleb Stewart Sep 02 '16 at 18:49
  • 1
    @Caleb1994: No, it wouldn't work in C89, because C doesn't allow for static initialization (hence "static init fiasco" isn't an issue in the C world). I also liked the lambda-based solution, but I didn't like that you had to append a `;` after the braces. Then at some point I realized we don't actually need any of those fancy features. – einpoklum Sep 02 '16 at 18:52