static变量看着有点晕,gdb汇编清醒清醒

大家都知道,C/C++里,变量是分类型的。

常见的,变量可以分为局部变量和全局变量;也可以分为静态变量和非静态变量。

组合一下,有局部静态、局部非静态、全局静态、全局非静态的区分。

关于这些变量的区分,不再展开,需要了解的读者,可以网络搜索或者随便翻翻C/C++方面的书籍,都有介绍的。

今天,我们这里要看的是局部静态变量结合C++的new构建单例类。

简单来讲,就是在获取单例的接口函数中,使用局部静态变量定义一个类指针,然后让这个类指针被new初始化。最后,返回该局部静态变量。

运行时,因为局部静态变量只初始化一次,这样,当我们调用该接口时,如果指针未初始化,则其将被初始化为new的对象,之后,每次再调用该接口时,指针初始化部分将不被执行,因此达到了类只实例化一次的目的。且因为这件事是编译器搞得,所以也间接达到了多线程安全的目的。

看个例子:

class TestA {
public:
    TestA(){}
    ~TestA(){}

private:
    int a;
    int b;
    int c;
    int d;
    int e;
};

TestA * getInstance() {
    static TestA* ptestA = new TestA;
    return ptestA;
}

int a = 0;
void testAsss() {
    a++;
    int b = 1;
    static TestA* ptestA = new TestA;
    int c = 1;
    int d = 1;
}

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

这里的getInstance就是实例写法。

不过这里,不是要研究单例。而是看到这块代码时候,有点晕,因为习惯思维原因,静态变量会在定义时候被编译器初始化,因而被这里的new给迷糊了。如果是个普通变量,可以理解编译器给变量分配地址空间,然后初始化。但是,对于new,编译器如何做到分配内存呢?如果说按照类占用空间分配内存可以做到,那么类中变量的初始化呢?这个是构造函数做的事情。

为了抹掉这个浆糊,特定写了上面这么一个简单的程序,然后分析汇编代码,看看编译器到底如何做的。

最终发现,静态变量只是让编译器在全局地址空间给其预留一份,定义时候,上述指针所在内存是被初始化为0的,也就是指针本身是NULL的。只有运行时,才会调用new,动态的分配对象内存,并将其地址给静态变量。

当第二次调用该函数时,编译器会检测,然后跳过这一行代码。

那么,编译是如何做的呢?其实,编译器会多分配一个空间,专门用于记录是否执行过静态变量所在行的代码

如果执行过后,该变量所在地址就会被写1,下次执行时,就跳过这部分,如上图红框所示。

以上是x86下的,arm下测试,也是同样的实现逻辑。

 

 

有时候,想来想去,看看汇编,再单步调试调试,就清醒了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙赤子

你的小小鼓励助我翻山越岭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值