linux c存储期、作用域、链接

存储期:

静态存储期分配的内存在程序执行期间一直存在
线程存储期分配的内存从线程生成到线程结束之前一直存在
自动存储期对象一般在块里面,当程序进入这个块时分配内存,退出这个块时就释放内存
动态存储期手动分配内存和释放内存(malloc,calloc)

作用域:

文件作用域(全局)
块作用域可见范围在块内
函数作用域仅用于goto标签
函数原型作用域函数原型的形参定义到结束,所以定义函数原型时,形参名编译器不关心,只要类型准确就行。

链接:

外部链接就是该对象在别的文件里也能被访问到
内部链接就是该对象只能在同一个文件里才能被访问到
无链接一般在块里,只能在块里才能被访问到

我们从例子中来解释

//a.c
//具有静态存储期,文件作用域,外部链接
char *name = "沧浪水";

//具有静态存储期,文件作用域,内部链接
static char *url = "https://www.51dev.com";
//main.c
#include <stdio.h>

//由于在别的文件声明了name为静态存储期,文件作用域,外部链接
//所以我们在这里可以直接拿来用
//extern就是用来表明该变量来自外部文件
extern char *name;

//由于在别的文件声明了name为静态存储期,文件作用域,内部链接
//在这里访问不到,所以下面语句无效
//extern char *url;

//不会产生命名冲突
char *url = "https://www.51dev.com";

int main(){
    //具有自动存储期、块作用域
    //另一种写法 auto char ch = 'a'
    char ch = 'a';
    
    puts(name);     //沧浪水
    puts(url);      //https://www.51dev.com
}
gcc main.c a.c
./a.out    #沧浪水

 

存储类别和动态内存分配

静态存储类别内存在编译的时候就已经确定,该类别的变量在程序开始的时候被创建,程序结束时被销毁。

自动存储类别内存在进入块时创建,离开块时销毁,内存数量会相应的增加和减少,这部分内存通常作为栈来处理,按顺序创建,按相反的顺序销毁。

动态分配的内存在调用malloc()或相关函数时创建,在调用free()时销毁,由程序员管理,内存会相对凌乱,速度通常也会比栈内存要慢。

如果一个函数手册表明函数返回值为静态分配的内存,那么该内存的数据一般在下次调用时会被覆盖,如果想永久保存,最好复制并分配到动态分配的内存。

static __thread char buffer[18];


char *
inet_ntoa (struct in_addr in)
{
  unsigned char *bytes = (unsigned char *) ∈
  __snprintf (buffer, sizeof (buffer), "%d.%d.%d.%d",
	      bytes[0], bytes[1], bytes[2], bytes[3]);

  return buffer;
}

上面这个 buffer 变量就是静态分配的内存, 只在本文件内可见, 如果去掉 static 修饰符, 还是静态分配的内存,只是变成了全局范围可见。

从上面可以看出, 库函数 inet_ntoa 调用时都会返回点分制ip地址, 每次都会被覆盖,所以如果要以后使用, 必须复制并保存返回结果。

所以阅读库函数手册时,一定要鉴别返回的变量内存是怎么分配的, 以备避免bug出现。

你可能感兴趣的