美文网首页C语言&嵌入式
内存模型与程序存在形式

内存模型与程序存在形式

作者: jkCodic | 来源:发表于2017-06-24 08:57 被阅读25次

    原标题名:变量异闻,内存变量存储与关键字

    编程思维

    1,编程的时候时常想想内存大概的模型已经划分的区域(主要四大区:静态存储区(数据段) 堆 栈 代码段),[数据段可存放静态数据和自由变量]变量 函数等在内存是在哪个区域的,加了修饰词有什么不同;[函数代码存放在代码段。声明的类如果从未使用,则在编译时,会优化掉,其成员函数不占代码段空间。
    补充:代码段、数据段、栈是CPU级别的逻辑概念,堆是语言级别的逻辑概念全局变量或静态变量,放在数据段,]
    [数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。]
    函数形参存放位置:主函数的是放在堆里面的,临时变量都是放在栈里面的;

    2,声明变量去"接住"你获得的数据进行操作;实现你要的功能,不要去管其他东西;会用是一个层次,理解低层实现原理是另外一个层次;

    内存主要分布:不可访问区、代码段、数据段、堆、栈、内核
        
    ①代码段:.text:用于存放用户代码;.init:用于存储系统给每一个程序自动添加的"初始化"代码
    
    ②数据段:.bass 专门存储未初始化的静态变量,它们的值会被初始化为为0,static int i;.data  专门存储已初始化的静态数据(静态数据:所有全局变量(全局变量默认初始化为0),及static的局部变量).rodata 存放只读数据(用const修饰),比如字符串、字符常量、整形等  char *p = "helloworld"; //"helloworld"只读字符串
    
    ③堆:它一块自由的内存,用户可以根据自己需求开辟空间大小,内存释放也是由用户自己进行释放(malloc realloc calloc开辟堆空间,释放free)
    
    ④栈:它是从0xC0000000往下增长的部分(后进先出),大概8M,专门存放局部变量(思考:如何判断栈是往下增长的 //先进入栈的变量在栈底)
    
    全局变量:存放.data当中,如果没有赋值系统默认初始化为0,如果没有被static修饰其它文件可以调用的变量
    
    Paste_Image.png

    一 内存效率相关(常见关键字)

    哪些区哪些特点 画图
    ①static作用(限制变量/函数(静态)的作用域;设置变量的存储域(主动分配内存在堆))
    1.全局变量时存储在不变区(静态变量区)但限制作用域;不能被模块外其它函数访问(静态函数类似,也可防冲突);
    *静态函数会被自动分配在一个一直使用的存储区,直到退出应用程序实例,避免了调用函数时压栈出栈,速度快很多;内部函数又称静态函数(static修饰,不怕同名)
    2.修饰局部变量时变存储区域"栈"为静态存储区(区别auto),代表该内存只被分配一次而且下次调用时仍维持上次的值;
    例:函数中定义,static int j = 10; //此时作用等同为全局变量,静态局部变量只初始化一次?->第二次调用不执行


    static修饰.png

    static总结 http://blog.csdn.net/damon_hoo/article/details/38903041

    1.静态局部变量:静态局部变量始终存在,生存期为整个源程序,作用域和局部变量是一样的,静态局部变量会被自动的初始化为0.

    2.静态全局变量:静态全局变量只能在一个文件中使用

    3.静态数据成员变量:描述整个类的特征,是整个类的成员,而不是一个对象的成员
    static int i;
    初始化静态数据成员在类体外进行,而且前面不加static,以免和一般静态变量混淆
    一般在cpp里面初始化,格式
    int CStudent::num = 0;

    4.静态成员函数:属于整个类的成员函数,是整个类的成员,而不是一个对象的成员,它的调用形式可以用对象来调用它,也可以用类的名字来调用它,静态成员函数可以有类名通过::直接调用,但是非静态成员函数只能通过对象名来调用。
    静态成员函数没有this指针,可以直接访问该类的静态成员和静态成员函数,而不能直接操作非静态的成员变量和非静态成员函数,如果静态成员函数中要引用非静态成员,则可以通过对象来引用,

    ②extern 修饰的变量(这里的变量给外部使用)或者函数不仅本文使用,外部文件也可以使用?
    温工:extern引用其他文件的函数

    ③register 数据类型 变量名;//声明寄存器变量
    register int i; //i就是一个寄存器变量
    1、用register修饰的变量告诉编译器不要优化,运行效率高
    2、不一定能100%分配变量为寄存器变量

    ④C中的宏与C++中的inline关键字声明频繁使用的小函数

    ①②对应静态存储期:static声明的局部变量具有静态存储持续期(static storage duration),或静态范围(static extent).虽然他的值在函数调用之间保持有效,但是其名字的可视性仍限制在其局部域内。静态局部对象在程序执行到该对象的声明处时被首次初始化;
    ③对应自动存储期(auto):变量在进入声明该变量的程序块时被建立,它在该程序块活动时存在,退出该程序块时撤销
    

    ⑤synchronized
    volatile三种作用:防止编译器优化;不会阻塞线程;解决变量在多个线程之间的可见性
    1.与该变量有关的运算,不要进行编译优化,以免出错
    ⑥inline内联函数 http://www.cnblogs.com/li-hao/archive/2013/03/15/2961713.html

    二 数组与指针

    void型指针不能解引用(目标类型未定),解引用前必须转化为某种具体的指针类型
    ④const修饰内容不能做任何改变
    例子:int *const p = &test1; //保护的是p里的内容,只能在定义里赋值
    //p = &test2; p为常量,不能再赋值
    const char p == char const p(修改p)
    (1)常量指针,不能通过这个指针改变变量的值,但是还是可以通过其他指针的引用或者变量来改变里面的值
    (2)常量指针指向的值不能改变,但是这并不意味着指针不能改变,指针可以指向其它变量的
    int test1 = 100;
    const int p;
    int pp;
    p = &test1; //指针与变量关联
    pp = &test1;
    test1 = 200; //通过变量改变里面的值
    pp = 70; //通过其他未用const指针来修改里面的值
    //
    p = 25; //error: assignment of read-only location ‘
    p’
    printf("
    p = %d\n",
    p);
    printf("test1 = %d\n",test1);
    char *const p:
    (1)指针常量:指针本身是一个常量,不能再指向别的地址
    (2) 指针常量里面的地址不能改变,但是地址中保存的值是可以改变的
    int test1 = 100;
    int test2 = 25;
    int const p = &test1; //保护的是p里的内容,只能在定义里赋值
    //p = &test2; p为常量,不能再赋值
    test1 =45;
    p = 70;
    printf("
    p = %d\n",
    p);
    printf("test1 = %d\n",test1);
    const int const p:指向常量的常指针。p里面的内容不可以改变,同时也不能通过p改变地址指向的内存

    ⑤数组初始化 数组求长-\n也算
    bzero menset 定义刚好的数组
    char buf[50]={0};//50个都为0
    char buf[50]={1};//只有第一个为1

    特殊定义:
    void func1(void);
    void func2(void (p)(void));
    typedef void(
    fi)(void (*f2)(void));
    f1 a ;
    意思:上面是一个指针(函数指针),指向返回类型为void,参数是一个函数指针的指针;

    复杂函数指针.png Paste_Image.png

    long在32位编译器下是4个字节
    ?引用传参的效率
    ⑥typedef重命名
    typedef char *p;
    p a="hello";//等价于char *a="hello";

    三 分配优化与安全溢出

    ⑦泄露与溢出
    堆栈溢出一般是循环的递归调用导致(或者大数据结构的局部变量)
    ⑧虚拟机溢出标志-can not write

    四 内存映射函数

    /*#include <sys/mman.h>
    void *mmap(void *addr, size_t length, int prot, int flags,
    int fd, off_t offset);
    addr ----- > 我们所申请的内存空间的起始地址
    NULL ----》系统自动分配
    length---- >内存空间的大小
    port ------>操作权限
    PROT_READ 可读
    PROT_WRITE 可写

    flags------> 共享属性
                MAP_SHARED   可以共享
                MAP_PRIVATE   私有
    fd--------> 硬件设备的文件描述符
    offset----》光标偏移量            
    

    int munmap(void addr, size_t length);/

    五 编译&优化等级

    http://blog.chinaunix.net/uid-25768133-id-3485479.html
    attribute ((packed))告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法。这个功能是跟操作系统没关系,跟编译器有关,gcc编译器不是紧凑模式的,我在windows下,用vc的编译器也不是紧凑的,用tc的编译器就是紧凑的

    相关文章

      网友评论

        本文标题:内存模型与程序存在形式

        本文链接:https://www.haomeiwen.com/subject/jhsjottx.html