关于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声明
浙公网安备 33010602011771号