
静态局部变量),只会被初始化一次,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。(限定生命周期)int autoAdd(void){
// 静态的局部函数延长声明周期,只在第一次调用时进行初始化
// 使用static修饰的局部变量的作用域依然是函数体的内部。
static int i = 100;
i++;
return i;
}
int main(int argc, const char *argv[]){
printf("%d\n", autoAdd()); // 101
printf("%d\n", autoAdd()); // 102
printf("%d\n", autoAdd()); // 103
return 0;
}
int autoAdd1(void){
// 静态的局部函数延长声明周期,只在第一次调用时进行初始化
// 如果没有初始化,默认初始化为0
int j; // 随机值
static int i;
i++;
return i;
}
int main(int argc, const char *argv[]){
printf("%d\n", autoAdd1()); // 1
printf("%d\n", autoAdd1()); // 2
printf("%d\n", autoAdd1()); // 3
return 0;
}
静态全局变量),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量(只能被当前文件使用,限定作用域)。#include
// 将全局变量使用static修饰声明为一个静态的全局变量
// 此变量只能在本文件中使用其他文件中不可以使用。
static int global = 2000;
// 将函数使用static修饰声明为一个静态的全局函数
// 此函数则只能在本文件中使用,其他外部文件不可以使用。
静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用(只能被当前文件使用)。1> static修饰局部变量,延长变量的生命周期到整个程序,
static修饰的局部变量如果初始化,则存到.data(初始化的全局数据段)段;
static修饰的局部变量如果没有初始化,则存到.bss(未初始化的全局数据段)段,默认初始值为0.
static修饰的局部变量只在函数第一次调用时被初始化一次,
后边如果在调用这个函数则不再进行初始化。、
2> static修饰全局变量,表示这个全局变量不可以在其他文件中使用。
3> static修饰函数,表示这个函数在其他源文件中不可以被调用。
(内存中读) ,而不是从 缓冲区 中获取值。以下转载:知乎仲一
1. 并行设备的硬件寄存器。
存储器映射的硬件寄存器通常加volatile,因为寄存器随时可以被外设硬件修改。
当声明指向设备寄存器的指针时一定要用volatile,它会告诉编译器不要对存储在这个地址的数据进行假设。
2. 一个中断服务程序中修改的供其他程序检测的变量。
volatile提醒编译器,它后面所定义的变量随时都有可能改变。因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中
读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的
值,如果这个变量由别的程序更新了的话,将出现不一致的现象。
3. 多线程应用中被几个任务共享的变量。
单地说就是防止编译器对代码进行优化.比如如下程序:
XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;
对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述
四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。如果键入
volatile,编译器会逐一的进行编译并产生相应的机器代码(产生四条代码)。
只读 的变量(不是常量),const修饰的变量在.rodata段 或者 在.stack(栈)中存放栈 中,代码块结束时释放#include
int main(int argc, char const *argv[])
{
char buf[4];
const int a=0;
buf[4]=97;
printf("a=%d\n",a);
//Vscode会报错:*** stack smashing detected ***
//已放弃 (核心已转储)
//但是QT4.11不会,而且a=97;
//说明:
/*
const修饰的变量,其实质是告诉程序员或编译器该变量为只读,如果程序员在程序中显示的修改一个只读变量,
编译器会毫不留情的给出一个error。而对于由于像数组溢出,隐式修改等程序不规范书写造成的运行过程中的修改,
编译器是无能为力的,也说明const修饰的变量仍然是具备变量属性的。
也就是 const修饰的变量是只读的变量(不是常量),const修饰的变量在.rodata段或者在.stack(栈)中存放
*/
return 0;
}

用const修饰 的 返回值类型是指针,那么函数返回值(即指针)的内容是不能被修改的,只能 赋给被 const修饰的指针。#include
const char *GetString(void)//定义一个函数
{
static int a=5;
char *p=(char *)&a;
return p;
}
int main(int argc, char const *argv[])
{
#if 0
char *str= GetString(); // 报警告,因为str没有被 const修饰
printf("*str=%d\n",*str);
*str=6; // 修改成功
printf("*str=%d\n",*str); // *str=6
#endif
#if 1
const char *str=GetString(); //正确,对返回[const char *]指针的值 只能读
printf("*str=%d\n",*str);
*str=6; // 报错,不可修改返回[const char *]指针的值
printf("*str=%d\n",*str);
#endif
return 0;
}
const int a = 10 这种,编译器会把它放到 符号表 中,不分配内存,当对其取地址时,会分配内存const int a = b ,那么也是会给a分配内存在c++中是否要为const全局变量分配内存空间,取决于这个const变量的用途
const int a = b ),那么就不分配内存空间,参考:c语言中const修饰的到底是常量还是变量?
参考:const修饰的变量的存储位置
参考:const、static变量存放位置注意全局和局部变量的CONST,const全局有的编译器直接当立即数存在ROM中
int a=5;
other()
{
int b=3;
static int c=2;
a+=5; b+=5; c+=5;
printf("%d,%d,%d\n",a,b,c);
c=b;
}
int main(void)
{
extern int a;
int b=0;
static int c;
a+=3;
other(); //13 8 7
b+=3;
other(); //18 8 13
}
#include
int main(int argc, const char *argv[])
{
// 1. 定义register类型的变量
register int r = 1000;
printf("r = %d\n", r);//1000
// 寄存器类型的变量不可以取地址
printf("&r = %p\n", &r); // error 错误
return 0;
}
自动类型(auto) : 一般局部变量为自动类型,定义局部变量时加auto和不加auto效果一样
非自动类型:全局变量:使用static修饰的局部变量, 使用static修饰的全局变量不能是auto类型。
局部变量是否使用auto修饰都是自动类型
#include
// 全局变量
int a = 100;
// auto int b = 200; // error 不可以使用auto修饰
// auto static int c = 200; // error 不可以使用auto修饰
int main(int argc, const char *argv[])
{
// 局部变量
int d = 300;
auto int e = 400; // 正确
// auto static int f = 500; // error 不可以使用auto修饰
return 0;
}
栈指针指向空位,每次存入时可以直接存入然后栈指针移动一格;
而取出时需要先移动一格才能取出
栈指针指向栈中最后一格数据,每次存入时需要先移动栈指针一格再存入;
取出时可以直接取出,然后再移动栈指针
栈指针移动时向地址增加的方向移动的栈;
向上拓展↑
栈指针移动时向地址减小的方向移动的栈;
向下拓展↓
进栈(先移动指针再入栈,指针往地址减小的方向移动);
出栈(先出栈,栈指针往地址增大的地方移动)。
进栈(先移动指针再入栈,指针往地址增大的方向移动);
出 栈(先出栈,栈指针往地址减小的地方移动)。
进栈(先进栈,栈指针往地址减小的方向移动);
出栈(先移动指针再出栈,栈指针往地址增大的方向移动)
进栈(先进栈,栈指针往地址增大的方向移动);
出栈(先移动指针再出栈,栈指针往地址减小的方向移动)
备注:
使用时不用纠结时哪一种栈结构,只要进栈和出栈用同一种栈结构就不会出错。
ARM默认使用满减栈