【STM32单片机入门-1】堆栈/全局变量,局部变量,静态全局变量,局部静态变量等

发布时间:2023年12月21日

1,堆栈对比

堆:由程序员分配和释放。容易产生碎片,使用方便,地址分配使用从下到上

栈:用来存放函数地址和局部参数,主函数使用时,要对函数的首地址断点保存,地址分配从上到下,用完自动释放

  • 0x2001,0000往下是未用的空间,可以做栈空间,只要不破坏全局变量,地址由程序员配置

2,静态存储区/全局变量/全局静态变量

静态存储区:它主要存放静态数据、全局数据和常量。

全局变量:全局变量存放在静态存储区,作用域是全局,整个声明周期都可以使用,其他文件如需要使用,需要添加extern

全局静态变量 (static):分配的内存与全局变量一样,也是在静态存储内存上,其生命周期也是与整个程序同在的,从程序开始到结束一直起作用,

全局静态变量作用域只在定义它的一个源文件内,其他源文件不能使用它

相同点

是由编译器自动分配和释放的,

初始化的全局变量和静态变量放在同一块内存区中

在调用main之前,内存先从FASH copy 数据(全局/静态变量),和复制全0段的(全局/静态变量)

全局变量和静态变量从0x2000,000开始存

3,局部变量和局部静态变量

分配内存是分配在栈存储区上的,其作用域也只是在局部函数内,在定义该变量的函数内,只要出了该函数,该局部变量就不再起作用,该变量的生命周期也只是和该函数同在。

局部变量

在栈里,临时给a 分配空间,

局部静态变量

分配的内存也是在静态存储内存上的,其第一次初始化后就一直存在直到程序结束,该变量的特点是其作用域只在定义它的函数内可见,出了该函数就不可见了。

4,代码举例

volatile int a = 0;// 全局初始化区  ①存放在内存起始单元0x2000,0000 
volatile char *p1; //全局未初始化区 ②存放在起始单元00x2000,0004 
void test(void)
{
    volatile  int t1=10;   //局部变量                      ④存放在栈空间  0x2000,0600  
    volatile static int t2 =0;//局部静态变量          ③存放在起始单元0x2000,0008     
 //    printf("%d %d  ",t1,t2);//防止代码被优化
}
void main()
{
    
    volatile int b  = 0;                                      //栈       ⑥存放在栈空间  0x20000620
    volatile char s[] = "abc";                        // 栈                ⑤存放在栈空间  0x2000061C 
    volatile char *p2;                                      //栈          存放在堆空间  0x20000618 
    volatile char *p3 = "123456";               //123456\0在常量区,p3在栈上。 0x20000614  
    volatile static int c =0;              //局部(静态)初始化区 ④存放在起始单元00x2000,000c
    test();
    
    //分配得来得10和20字节的区域就在堆区。
     p1 = (char *)malloc(10);
     p2 = (char *)malloc(20);
    volatile char *p4= (char *)malloc(20);  //存放在堆空间 0x20000610
    strcpy(p2, "123456");                                 //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
    
    printf("%d %d %d %d  %d %d  %d ",a,s[0],&p3,c,p1,b,&p2,&p4);//防止代码被优化
}

来自文心一言的解答

这段代码中的变量存储位置以及内存分配涉及到C语言的内存布局和内存管理。首先,我们逐一回答您的问题。

  1. t1存放在栈空间中,请问栈空间的起始地址在哪里配置的?

栈空间的起始地址和大小通常是在程序启动时由操作系统配置的。具体的配置方式依赖于操作系统和硬件架构。在嵌入式系统或低级编程中,可能会直接设置栈指针寄存器来指定栈的起始和结束位置。在高级操作系统中,如Linux或Windows,这通常是进程创建时的一部分自动管理。

2. p2,p3,p4 都是堆空间分配地址的吗?

p2p4 是通过 malloc 分配的,所以它们指向的地址是在堆空间中的。而 p3 是一个指向字符串常量 "123456" 的指针,这个字符串常量通常存放在程序的常量区,不是堆空间。

3. 这个地址位置也和栈在一个地址范围吗?

不一定。堆和栈通常是两个不同的内存区域,它们有自己的起始和结束地址。具体的位置和大小取决于操作系统、编译器设置和硬件架构。在某些架构和操作系统中,堆和栈可能是相邻的,但它们仍然是逻辑上分离的区域。

现在,关于代码中的内存布局:

ap1 是全局变量,它们存放在全局/静态存储区。

t1 是局部变量,存放在当前函数的栈帧中。

t2 是局部静态变量,存放在全局/静态存储区,但其生命周期局限于定义它的函数内。

b, s, p2, p3, 和 c 都是在 main 函数内的局部变量。其中,sb 存放在栈上;p2p3 本身存放在栈上,但它们通过 malloc 分配的内存位于堆上;c 是局部静态变量,存放在全局/静态存储区。

p4 也是一个局部变量,存放在栈上,但通过 malloc 分配的内存位于堆上。

请注意,具体的内存地址(如0x2000,0000、0x2000,0004等)在代码中只是示例,实际运行时可能会有所不同。另外,当您提到 "防止代码被优化" 时,使用 volatile 和打印变量的方式确实可以防止某些编译器优化,但这不是一个通用的或推荐的方法。更好的方法是使用适当的编译器优化设置和/或编译器特定的属性或注解来确保代码的正确性和性能。

5,总结

文章来源:https://blog.csdn.net/cengqiu4314/article/details/135128289
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。