【问题标题】:What is static block in c or c++? [duplicate]什么是 C 或 C++ 中的静态块? [复制]
【发布时间】:2011-03-23 03:37:08
【问题描述】:

我想通过一个例子知道什么是c或c++中的静态块?我知道什么是静态的,但静态和静态块有什么区别?

【问题讨论】:

  • 这两种语言都没有。
  • 检查你的标题是否有 #define 块......也许有人定义了“块”......
  • @Neil - 我正在通过谷歌搜索引擎探索“静态”概念,当我在谷歌输入“静态块”时,我发现一个选项说明“c 中的静态块”
  • @Abhi 这证明了……什么?
  • 在Java中引入了一个静态块,在C#中也存在,用于初始化静态成员。

标签: c++ c static-block


【解决方案1】:

另一种选择是您可能正在寻找静态的类比 Java中的块。加载应用程序时运行的代码块。 C++ 中没有这样的东西,但可以通过使用 a 的构造函数来伪造它 静态对象。

foo.cpp:

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


static StaticBlock staticBlock;

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

}

但是。我以前被这个咬过,因为它是 C++ 的一个微妙的边缘案例 标准。如果 main 调用的任何代码都无法访问静态对象 静态对象的构造函数可能会被调用,也可能不会被调用。

我发现使用 gcc hello 会得到输出,使用 Visual Studio 会 不是。

【讨论】:

  • +1:另外,初始化顺序是不确定的,也会让人很头疼。我也想看看一个可靠的静态初始化框架。
  • +1 用于提及可能无法到达的情况。您确定它没有被调用,而不仅仅是在编译时被完全删除吗?我怀疑即使 gcc 也会使用足够的优化标志来做到这一点。
  • @EntangledLoops:不,你可以放心is not being removed。 bradgonesurfing:为什么要使用类? static-initialize an int with with a function 还不够吗?
【解决方案2】:

我在 The Code Project 上找到了 this 答案。它涉及一个额外的静态变量,但我相信它比 bradgonesurfing 的答案更可靠。基本上是这样的:

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

这也意味着,就像 Java 的静态块一样,您不需要实际拥有 class Foo 的实例,这在类可以获取大量数据时很有用,您只需要在之前自动调用一些东西它加载,而不是实例化它的额外实例。您可以测试该确切的代码块。我刚刚编译了它(用 static_init() 的一点输出,并让 main() 打印 Foo::__st_init,只是为了确保),它工作得很好。

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

编辑:

抱歉,这么晚了,但我测试了bradgonesurfing 提到的内容:

如果你测试它,我在 main 中访问变量“只是为了确保” 您确保变量是可访问的,因此变量将 被初始化,因此 static_init 将被调用。你确定吗 如果您不打印 Foo::__st_init

,则执行

我在 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;
}

我使用g++ ./main.cpp -o main 编译并运行它并收到友好的“Hello,World!”我的控制台上的消息。为了彻底,我也编译了相同的版本,但没有打印并使用g++ ./main.cpp -g -o main编译。然后我用 gdb 运行可执行文件并得到以下结果:

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

这是 g++ 的最新版本输出:g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2

【讨论】:

  • 如果你测试它,我在 main 中访问变量“只是为了确保”你确保变量是可访问的,因此变量将被初始化,因此 static_init 将被调用。如果你 dont print Foo::__st_init 你确定它会执行吗
  • 这是一个很好的观点,bradgonesurfing。我已经用足够的测试更新了我的答案,而且它似乎仍然有效。抱歉迟到了两年,如果你读过这篇文章……我不知道为什么我从来没有回复过。
  • 感谢您提供在某些情况下有效的方法,但不幸的是,如果您在单独的静态库中调用静态方法,这将不起作用...即使您包含 Foo main.cpp 中的标头。
  • Caleb445:你不觉得这很麻烦吗?我的意思是,即使使用相同的方法,您也可以/应该对其进行宏化,使其使用起来不那么冗长。
【解决方案3】:

C/C++ 中没有名为“静态块”的概念。然而,Java 有它,“静态块”是一个类的初始化代码块,它在创建类的第一个实例之前只运行一次。基本概念“只运行一次”可以在 C/C++ 中使用静态变量进行模拟,例如:

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

但这不是线程安全的。有时在存在多个线程的情况下使其正常工作可能会很困难和棘手。

【讨论】:

    【解决方案4】:

    在 C++ 中有匿名命名空间的概念。

    foo.cpp:
    
    namespace {
        int x;
        int y;
    }
    

    在 C 中获得同样的效果

    foo.cpp:
    
    static int x;
    static int y;
    

    简单来说,编译器不会从 翻译单元被声明为静态或 在匿名命名空间中。

    【讨论】:

    • “导出符号”是什么意思? C++ 标准没有定义这个术语。但是,它谈到了“联系”,就联系而言,据我所知,您的主张是错误的。这两个例子没有相同的效果。来自匿名命名空间的xy 具有外部链接,而另外两个具有内部链接。不过我明白你的意思。您的意思是其他翻译单元不能按名称引用这些变量。
    • 匿名命名空间中的项目只有内部链接publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/… 好吧,IBM 这么说。有没有人在这方面有指向 C++ 标准的指针?
    • 好的。我找到了一份标准的副本,上面写着以下内容。 “虽然未命名命名空间中的实体可能具有外部链接,但它们实际上是由其翻译单元唯一的名称限定的”我怀疑在实践中它将取决于编译器,但效果是相同的。
    【解决方案5】:

    虽然 C++ 确实没有静态块作为语言的一部分,但您可以在您(作为用户)不必使用任何类或命名空间的情况下实现静态块,并且可以编写:

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

    或任何你想要的。但是,您不能在类中拥有它们,仅在文件范围内。在我的answer 中查看相关问题的详细描述,以及static_block.h here 的代码。

    注意:这不需要 C++11,并且可以很好地与旧编译器配合使用。

    【讨论】:

    • 这是一个有趣的解决方案,但值得一提的是,除了您发布的代码块之外,还有更多内容。需要定义一些宏,它使用 C++11 lambda。我同意您的解决方案提供了一种更精简(也更优雅)的方法。它使用了我当时不熟悉的 C++11 特性。我的答案是 4 年前写的,当时 C++11 标准还很新,还不一定是主流。
    • @Caleb1994:实际上,这种机制与 C++11 无关,它是 C++98,甚至可能更早。不使用初始化列表、类,没有什么花哨的——只是一些用于唯一标识符的预处理器内置函数,以及 C++ 具有静态初始化的事实。无论如何,我包含了一个#include 声明和一个代码链接。
    • 哎呀,我读错了答案。是的,您的解决方案没有花哨的东西。你说得对。虽然,您上面的 C++11 lambdas 解决方案看起来相当不错。它可以在函数范围内使用(虽然我个人没有测试过)。您的解决方案是程序性的,我认为甚至可以在 C89 中使用,哈哈。
    • @Caleb1994:不,它在 C89 中不起作用,因为 C 不允许静态初始化(因此“静态初始化失败”在 C 世界中不是问题)。我也喜欢基于 lambda 的解决方案,但我不喜欢您必须在大括号后附加 ;。然后在某个时候,我意识到我们实际上并不需要任何这些花哨的功能。
    猜你喜欢
    • 2011-01-18
    • 2011-12-17
    • 2011-06-02
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 2012-03-21
    • 2013-10-14
    • 1970-01-01
    相关资源
    最近更新 更多