0x01 存储类别
1、作用域
一个C变量的作用域可以是块作用域、函数作用域、函数原型作用域或文件作用域。
1.1 块作用域:
块是用一对花括号括起来的代码区域。比如函数体就是一个块。定义在块中的变量具有块作用域,块作用域变量的可见范围是从定义处到包含该定义的块的末尾
1.2 函数作用域
仅用于goto语句的标签。一个标签首次出现在函数的内层块中,它的作用域也延伸至整个函数
1.3 函数原型作用域
用于函数原型中的形参名,作用范围是从形参定义处到原型声明结束。这意味着,编译器在处理函数原型中的形参时只关心它的类型,而形参名通常无关紧要。
1.4文件作用域
变量的定义在函数外面,具有文件作用域,从它的定义处到该定义所在文件的末尾均可见。
2、链接
C变量有3种链接属性:外部链接、内部链接或无链接。具有块作用域、函数作用域或函数原型作用域的变量都是无链接变量。这意味着这些变量属于定义他们的块、函数或原型私有。具有文件作用域的变量可以是外部链接或内部链接。外部链接变量可以在多文件程序中使用,内部链接变量只能在一个文件中使用。当一个文件作用域变量用static修饰时就是内部链接
3、存储期
C有4种存储期:静态存储期、线程存储期、自动存储期、动态分配存储期
- 静态存储期:在程序的执行期间一直存在,文件作用域具有静态存储期
- 线程存储期:用于并发程序设计,程序执行可被分为多个线程。从被声明到线程结束一直存在
- 自动存储期:块作用域的变量通常都具有自动存储期,当程序进入定义这些变量的块时,为这些变量分配内存,当退出这个块时,释放刚才为变量分配的内存
4、存储类别说明符
- auto:表名变量是自动存储期,只能用于块作用域的变量声明中。由于在块中声明的变量本身就具有自动存储期,所以使用auto主要是为了明确表达要使用外部变量同名的局部变量的意图。
- register 说明符也只用于块作用域的变量,它把变量归为寄存器存储类别,请求最快速度访问该变量。同时,还保护了该变量的地址不被获取。
- static 说明符创建的对象具有静态存储期,载入程序时创建对象,当程序结束时对象消失。如果static 用于文件作用域声明,作用域受限于该文件。如果 static 用于块作用域声明,作用域则受限于该块。
- extern 说明符表明声明的变量定义在别处。如果包含 extern 的声明具有文件作用域,则引用的变量必须具有外部链接。如果包含 extern 的声明具有块作用域,则引用的变量可能具有外部链接或内部链接,这接取决于该变量的定义式声明。
5、小结
0x02 存储类别和函数
函数也有存储类别,可以是外部函数(默认)或静态函数。外部函数可以被其他文件的函数访问,但是静态函数只能用于其定义所在的文件。
double gamma(double); /* 该函数默认为外部函数 */
static double beta(int, int);
extern double delta(double, int);
在同一个程序中,其他文件中的函数可以调用gamma()和delta(),但是不能调用beta(),因为以static存储类别说明符创建的函数属于特定模块私有。这样做避免了名称冲突的问题,由于beta()受限于它所在的文件,所以在其他文件中可以使用与之同名的函数。
通常的做法是:用 extern 关键字声明定义在其他文件中的函数。这样做是为了表明当前文件中使用的函数被定义在别处。除非使用static关键字,否则一般函数声明都默认为extern。
在rand0.c文件里:
static unsigned long int next=1;
unsigned int rand0(void)
{next=next*1103515245+12345;return (unsigned int) (next / 65536 )%32768;
}
在r_drive0.c文件里
#include "stdio.h"extern unsigned int rand0(void);int main(void)
{int count;for(count = 0;count<5;count++)printf("%d\n",rand0());return 0;
}
next是静态内部链接,存储期在程序的执行期间一直存在,作用域是rand0.c文件,其他就不可以访问了。
unsigned int rand0(void)是外部函数,其他文件可以调用,用 extern 关键字声明定义rand0.c文件里
0x03 分配内存 malloc()和free()
- malloc():接收一个参数,是所需内存的字节数,返回动态分配内存块的首字节地址。如果 malloc()分配内存失败,将返回空指针。malloc会找到合适的空闲内存块,这样的内存是匿名的,malloc()函数可用于返回指向数组的指针、指向结构的指针等,所以通常该函数的返回值会被强制转换为匹配的类型
- free()函数的参数是之前malloc()返回的地址,该函数释放之前malloc()分配的内存,一些操作系统在程序结束时会自动释放动态分配的内存,但是有些系统不会。为保险起见,请使用free(),不要依赖操作系统来清理。
- malloc()和free()的原型都在stdlib.h头文件中。
- 因为char表示1字节,malloc()的返回类型通常被定义为指向char的指针。然而,从ANSI C标准开始,C使用一个新的类型:指向void的指针,把指向 void的指针赋给任意类型的指针完全不用考虑类型匹配的问题
#include "stdlib.h"
#include "stdio.h"int main(void)
{double *ptd;int max=5;int number;int i;ptd=(double *)malloc(max*sizeof(double));for(i=0;i<max;i++){ptd[i]=i;printf("%f\n",ptd[i]);}free(ptd);return 0;}
上面的程序是动态分配数组
反汇编:
6: double *ptd;
7: int max=5;
00401028 C7 45 F8 05 00 00 00 mov dword ptr [ebp-8],5
8: int number;
9: int i;
10:
11: ptd=(double *)malloc(max*sizeof(double));
0040102F 8B 45 F8 mov eax,dword ptr [ebp-8]
00401032 C1 E0 03 shl eax,3
00401035 50 push eax
00401036 E8 95 00 00 00 call malloc (004010d0)
0040103B 83 C4 04 add esp,4
0040103E 89 45 FC mov dword ptr [ebp-4],eax
12:
13: for(i=0;i<max;i++)
00401041 C7 45 F0 00 00 00 00 mov dword ptr [ebp-10h],0
00401048 EB 09 jmp main+43h (00401053)
0040104A 8B 4D F0 mov ecx,dword ptr [ebp-10h]
0040104D 83 C1 01 add ecx,1
00401050 89 4D F0 mov dword ptr [ebp-10h],ecx
00401053 8B 55 F0 mov edx,dword ptr [ebp-10h]
00401056 3B 55 F8 cmp edx,dword ptr [ebp-8]
00401059 7D 2A jge main+75h (00401085)
14: {
15: ptd[i]=i;
0040105B DB 45 F0 fild dword ptr [ebp-10h]
0040105E 8B 45 F0 mov eax,dword ptr [ebp-10h]
00401061 8B 4D FC mov ecx,dword ptr [ebp-4]
00401064 DD 1C C1 fstp qword ptr [ecx+eax*8]
16: printf("%f\n",ptd[i]);
00401067 8B 55 F0 mov edx,dword ptr [ebp-10h]
0040106A 8B 45 FC mov eax,dword ptr [ebp-4]
0040106D 8B 4C D0 04 mov ecx,dword ptr [eax+edx*8+4]
00401071 51 push ecx
00401072 8B 14 D0 mov edx,dword ptr [eax+edx*8]
00401075 52 push edx
00401076 68 1C 60 42 00 push offset string "%f" (0042601c)
0040107B E8 D0 1F 00 00 call printf (00403050)
00401080 83 C4 0C add esp,0Ch
17: }
00401083 EB C5 jmp main+3Ah (0040104a)
18: free(ptd);
00401085 8B 45 FC mov eax,dword ptr [ebp-4]
00401088 50 push eax
00401089 E8 C2 0A 00 00 call free (00401b50)
0040108E 83 C4 04 add esp,4
19:
20:
ptd=(double )malloc(maxsizeof(double));的反汇编是:
0040102F 8B 45 F8 mov eax,dword ptr [ebp-8]
00401032 C1 E0 03 shl eax,3
00401035 50 push eax
00401036 E8 95 00 00 00 call malloc (004010d0)
0040103B 83 C4 04 add esp,4
0040103E 89 45 FC mov dword ptr [ebp-4],eax
先将max的值传给eax,左移eax三位,相当于eax乘以8,就是40,刚好是传给malloc的参数值,然后压栈,调用malloc函数,再把eax存入dword ptr [ebp-4]中。
free(ptd);反汇编:
00401085 8B 45 FC mov eax,dword ptr [ebp-4]
00401088 50 push eax
00401089 E8 C2 0A 00 00 call free (00401b50)
0040108E 83 C4 04 add esp,4
先把dword ptr [ebp-4]的值传给eax,就是40,是malloc分配内存的大小,eax入栈,调用free函数,释放这段内存