原标题名:变量异闻,内存变量存储与关键字
编程思维
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,参数是一个函数指针的指针;
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的编译器就是紧凑的
网友评论