关于C语言中static,以及存储期/区的一些个人见解

 

 

 

本截图摘自C primer plus 376面

上图表示数据存在时间。与下面的存储空间无关。

静态存储区包含:Bss、数据段、代码段。

BSS段BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。

数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

(这一块网上资料比较杂,我也没看过什么权威的书籍,在网上还提到了一个常量区)

——————————————————————————————————

动态存储区包含:堆区,栈区。

:会存放函数的返回地址、参数和局部变量。C语言中自动变量(auto)表示“进入该块后,自动分配内存”,为默认方式。(C和C++中auto有很大不同,C++表示类型推导)

#include <stdio.h>
char * favorite_fruit()
{
    char deciduous[]="apple";
    return deciduous;
}
int main()
{
    printf("hello\n");
    printf("%s",favorite_fruit);
}

 

得到的结果是

 

 

原因如下:

当进入该函数时,白动变量 deciduous在堆栈中分配。 当函数结束后,变量不复存在,它所用的堆栈空间被回收,可能在任何时候被覆盖。这样,指针就失去了有效性(引用不存在的东西),被称为虽垂指针(dangling pointer)”——它们并不引用有用的东西,而是冠在地址空间内。如果想返回--个指向在函数内部定义的变晕的指针时,要把那个变量声明为static。这样就能保证该变量被保存在数据段中而不是堆栈中。该变量的生命期就和程序一样长,当定义该变量的函数退出时,该变量的值依然能保持。当该禹数下次进入时,该值依然有效。

当我们加入static后,变量存储在静态存储区.数据段

static char deciduous[]="apple";

 

上述例子摘自《C专家编程》)

堆:我们通过 new 算符和 malloc 函数分配得到的空间。

 

 

Static

静态无链接

静态变量(static variable〉听起来自相矛盾,像是一个不可变的变量。实际上,静态的意思是该变量在内存中原地不动,并不是说它的值不变。具有文件作用域的变量自动具有(也必须是)静态存储期。前面提到过,可以创建具有静态存储期、块作用域的局部变量。这些变量和自动变量一样,具有相同的作用域.但是程序离开它们所在的函数后,这些变量不会消失。也就是说,这种变量具有块作用域、无链接,但是具有静态存储期。计算机在多次函数调用之间会记录它们的值。在块中(提供块作用域和无链接)以存储类别说明符static(提供静态存储期)声明这种变量。程序清单12.3演示了一个这样的例子。

静态变量的存储位置为静态存储区,具有和自动变量一样的作用域,计算机可以多次调用。

#include <stdio.h>
void trystat(void);

int main(void)
{
    int count;
    for (count = 1; count <= 3; count++)
    {
        printf("Here comes iteration %d:\n", count);
        trystat();
    }
    return 0;
}
void trystat(void)
{
    int fade = 1;
    static int stay = 1;
    printf("fade = %d and stay = %d\n", fade++, stay++);
}

 

 

结果为

Here comes iteration 1:

fade = 1 and stay = 1

Here comes iteration 2:

fade = 1 and stay = 2

Here comes iteration 3:

fade = 1 and stay = 3

可见自动变量和静态变量在函数调用的区别:自动变量在每次调用时都会初始化,但静态变量只在编译函数时初始化一次,同时如果没有显式初始化静态变量,则值为0,而自动变量则是其内存的值,具有不确定性。

下面两个声明很相似:int fade = 1;
static int stay = 1;
Ⅰ条声明确实是trystat ()函数的一部分,每次调用该函数时都会执行这条声明。这是运行时行为。第⒉条声明实际上并不是trystat()函数的一部分。如果逐步调试该程序会发现,程序似乎跳过了这条声明。这是因为静态变量和外部变量在程序被载入内存时已执行完毕。把这条声明放在trystat()函数中是为了告诉编译器只有trystat ()函数才能看到该变量。这条声明并未在运行时执行。
不能在函数的形参中使用static:
int wontwork (static int flu) ; l//不允许
“局部静态变量”是描述具有块作用域的静态变量的另一个术语。阅读一些老的C文献时会发现,这种存储类别被称为内部静态存储类别(internal static storage class)。这里的内部指的是函数内部,而非内部链接。

外部链接的静态变量

并不是所有静态变量都有static作为修饰,当变量在所有函数外声明时,其便是具有外部链接的静态变量。外部链接的静态变量的特点是可以在其他文件中使用的静态变量。

 

外部链接的静态变量具有文件作用域、外部链接和静态存储期。该类别有时称为外部存储类别(externalstorage class ),属于该类别的变量称为外部变量(external variable)。把变量的定义性声明(defining declaration)放在在所有函数的外面便创建了外部变量。当然,为了指出该函数使用了外部变量,可以在函数中用关键字extern再次声明。如果一个源代码文件使用的外部变量定义在另一个源代码文件中,则必须用extern在该文件中声明该变量。如下所示:

/*main.c*/
#include <stdio.h>
#include "Try.h"
extern int num2;
int main() {
    printf("Hello, World!\n");
    printf("%d\n",num);
    printf("%d",num2);
    return 0;
}
//try.c #include "Try.h" int num=100; int num2=10; //Try.h #ifndef AGAIN_TRY_H #define AGAIN_TRY_H #include "stdio.h" extern int num; #endif //AGAIN_TRY_H

 

 

文件中定义了两个外部链接的静态变量num2是在try.c文件中声明并定义,在main中必须使用extern,

num则在Try.h中声明,在Try.c定义,在main中引用,因为main中包含了"Try.h"。

应该注意定义只能一次,但声明没有限制

 

 关于定义和声明

例:{

尤其是对于变量来说。

extern int a;//声明一个全局变量a

int a; //定义一个全局变量a

extern int a =0 ;//定义一个全局变量a 并给初值。

int a =0;//定义一个全局变量a,并给初值,

第四个 等于 三个,都是定义一个可以被外部使用的全局变量,并给初值。

糊涂了吧,他们看上去可真像。但是定义只能出现在一处。也就是说,不管是int a;还是extern int a=0;还是int a=0;都只能出现一次,而那个extern int a可以出现很多次。

原文链接:https://blog.csdn.net/viafcccy/article/details/88293897}

只能使用常量初始化文件作用域变量,故下方代码不合法:

int x2=2*num;//num不是常量

 

内部链接的静态变量

该存储类别的变量具有静态存储期、文件作用域和内部链接。在所有函数外部(这点与外部变量相同),用存储类别说明符static定义的变量具有这种存储类别:

static int num2=20;
int main() {
    extern  num2;
    printf("%d",num2);
    return 0;
}

 

外部链接的静态变量可以在同一程序(项目?)的任意文件中使用,但内部链接的静态变量只能在同一个文件中使用。

最后附上表一张

 

 

 欢迎大佬指出错误

参考:extern、定义和声明_viafcccy的博客-CSDN博客_extern声明

数据段、代码段、BSS段、堆栈段_Leo丶Fun的博客-CSDN博客_数据段

数据段、代码段、堆、栈详解_Colorful_lights的博客-CSDN博客

posted @ 2022-06-19 16:59  五十载  阅读(862)  评论(0)    收藏  举报