C++ 内存模型(1)--static

面试过C++的同学都知道,面试官最喜欢问的问题之一就是C++内存模型问题。
例如static 、堆、栈等
网上对这方面的文章很多,但很多都是互相转发。并没有真正验证过。
下面我们通过真实代码来分析C++中,带static的变量的内存布局。

背景:我们知道,在c++中, static 可以用在几个地方:
1)函数修饰变量
2)修饰全局变量
3)类中,修饰类的静态成员变量
4)在类中,修饰表态函数
5)函数定义开头,修饰函数


问题1:函数中static 变量的内存是如何的?

#include "Apple.hpp"

static int g_a = 32;
static int g_b = 32;
static int g_c;

void test(){
    int a = 3;
    int b = 4;
    int c = 3;
    int d = 4;
    
    
    printf("局部变量 a,b,c,d  \n%p  %p  %p  %p\n",&a,&b,&c, &d);
    static int sa = 32;
    static int sb = 32;
    static int sc = 32;
    static int sd;
    
    printf("函数中的 static 变量 \n:sa,sb,sc,sd \n%p  %p  %p  %p\n",&sa,&sb,&sc, &sd);
    
    printf("全局 static 变量 g_a g_b g_c:\n%p %p %p\n",&g_a,&g_b,&g_c);

}

void test1(){
}

int main(int argc, const char * argv[]) {
    // insert code here...
    
    test();
};

输出结果:

0x7fff5fbff7bc  0x7fff5fbff7b8  0x7fff5fbff7b4  0x7fff5fbff7b0
函数中的 static 变量 
:sa,sb,sc,sd 
0x1000020ac  0x1000020b0  0x1000020b4  0x1000020c0
全局 static 变量 g_a g_b g_c:
0x1000020b8 0x1000020bc 0x1000020c4

分析:

//1. g_a, g_b的空间地址是连续的,相差为4,正好和int所占内存空间一致
//2. 地址是递增的。
static int g_a = 32; //0x1000020b8
static int g_b = 32;//0x1000020bc
static int g_c;//0x1000020c4

void test(){
//从a,b,c,d 的空间地址看出,函数的局部变量是存放在栈上,并且空间地址是递减的,这也符合栈空间的特点(众所周知,栈空间逆向生长)。
    int a = 3;//0x7fff5fbff7bc
    int b = 4;//0x7fff5fbff7b8
    int c = 3;//0x7fff5fbff7b4
    int d = 4;//0x7fff5fbff7b0
    
//1. g_a, g_b,g_c的空间地址是连续递增,相差为4,正好和int所占内存空间一致
//2. sd地址断开了
    static int sa = 32;//0x1000020ac
    static int sb = 32;//0x1000020b0
    static int sc = 32;//0x1000020b4
    static int sd;      //0x1000020c0
    

把上面结果的static 变量按地址递增排序为:
sa< sb< sc < g_a < g_b < sd < g_c
可以得出两个结论:
1)函数中的static变量是放到和全局变量个内存区的,也就是全局内容区。
2)编译器给这些static 或 全局变量在内存中的位置为:先函数,再全局。先有值的变量,再无初始值的变量。


问题2:类中的static变量内存是如何分配的

为了搞清楚这个问题,我们先定义一个类Apple
头文件

class Apple{
public:
    static int m_static_num;
};

实现

int Apple::m_static_num = 3;

测试

static int g_a = 32;
static int g_b = 32;
static int g_c ;
int g_d = 3;//新增加

void test(){
    int a = 3;
    int b = 4;
    int c = 3;
    int d = 4;
    
    
    printf("局部变量 a,b,c,d  \n%p  %p  %p  %p\n",&a,&b,&c, &d);
    static int sa = 32;
    static int sb = 32;
    static int sc = 32;
    static int sd;
    
    printf("函数中的 static 变量 \n:sa,sb,sc,sd \n%p  %p  %p  %p\n",&sa,&sb,&sc, &sd);
    
    printf("全局 static 变量 g_a g_b g_c g_d:\n%p %p %p %p\n",&g_a,&g_b,&g_c,&g_d);

}

void test1(){
}

int main(int argc, const char * argv[]) {
    // insert code here...
    
    test();
    
    Apple apple = Apple();
    printf("\napple object address %p , apple member address %p\n",&apple,&apple.m_static_a);
}

输出结果:
注意:以下结果,原全局变量,static变量的地址变化了。是因为原来代码中有些其他未列出的变量。单独分析这次结果不影响。

局部变量 a,b,c,d  
0x7fff5fbff7ac  0x7fff5fbff7a8  0x7fff5fbff7a4  0x7fff5fbff7a0
函数中的 static 变量 
:sa,sb,sc,sd 
0x10000101c  0x100001020  0x100001024  0x100001030
全局 static 变量 g_a g_b g_c:
0x100001028 0x10000102c 0x100001034

apple object address 0x7fff5fbff7c8 , apple member address 0x100001018

分析:
m_static_num

结论:
1)类的static变量,函数中的static变量,无static的全局变量,带static的全局变量 都是放到同一个内存区,全局内存区。
2)全局变量的初始化顺序,按Bjane的说法是变量定义的先后顺序,不同文件的看编译器具体实现,不做要求。全局变量(包括static)在main函数之前初始化( 动态连接库的情况下是在连接的时候初始化),在main函数结束后清理。

下一章节分析类,函数,指针在内存中的分布

你可能感兴趣的:(C++ 内存模型(1)--static)