变量和常量是程序处理的两种基本数据对象。声明语句说明变量的名字及类型,也可以指定变量的初始值。
变量占用了内存的一块区域,不同数据类型的变量占用的字节大小各不相同。
类型 | 字节大小 |
---|---|
char | 1 |
short | 2 |
int | 4 |
long | 4 |
char * | 4 |
float | 4 |
double | 8 |
以上是C语言基本数据类型占用字节大小。在32位环境下。
声明变量需要声明变量的类型和名字。名字指定了那块内存区域,对名字的引用,就是对那块内存的引用。
局部变量
int main(void)
{
int i;
char ch;
i=32;
ch='a';
return 0;
}
变量i占用了4字节的内存,而ch占用了一字节的内存。i=32对4字节内存赋值为32,ch=‘a’对一字节内存赋值为’a’。4字节内存是内存连续的4个字节。
将c代码翻译成汇编我们将看的更加清楚。
.text
.global main
main:
pushl %ebp
movl %esp,%ebp
subl $5,%esp
movl $32,-4(%ebp)
movb $'a',-5(%ebp)
movl $0,%eax
leave
ret
.text指定以下片段是代码段。.global main声明main函数是全局函数。main:是函数的名字。
pushl %ebp; movl %esp,%ebp用于建立临时的栈帧,leave;ret用于销毁临时的栈帧。这将在函数章节中详细解释。
我们详细看中间的3行代码。
subl $5,%esp,栈指针减去5,在栈空间中申请了5个字节的空间。由于前面movl %esp,%ebp。%ebp=%esp。之后subl $5,%esp,所以内存地址可以使用%ebp作为基址来引用。
movl $32,-4(%ebp),将32写入-4(%ebp),-3(%ebp),-2(%ebp),-1(%ebp)这4个字节中,当然是按照小端写入的。
movb $‘a’,-5(%ebp),将’a’写入-5(%ebp)字节中。
这里用到了两个指令,如下所示。
指令 | 功能 | 描述 |
---|---|---|
movl S,D | S->D | 赋值四个字节的数据 |
movw S,D | S->D | 赋值两个字节的数据 |
movb S,D | S->D | 赋值一个字节的数据 |
按照指令,我们还可以给char,short,int ,long ,char *等基本数据类型赋值。
int main(void)
{
long l=1;
int i=2;
short s=3;
char c='a';
return 0;
}
汇编代码
.text
.global main
main:
pushl %ebp
movl %esp,%ebp
subl $11,%esp
movl $1,-4(%ebp)
movl $2,-8(%ebp)
movw $3,-10(%ebp)
movb $'a',-11(%ebp)
movl $0,%eax
leave
ret
以上所说的变量都是局部变量,那全局变量是怎么样的呢?
全局变量
全局变量包括定义在函数外的变量,static 变量和定义在函数内的static 变量。
int array_len=20;
static int array_max=12;
int main(void)
{
static int max=12;
array_len=30;
array_max=15;
max=22;
return 0;
}
汇编代码
.data
.global array_len
array_len:.long 20
array_max:.long 12
max.1936:.long 12
.text
.global main
main:
pushl %ebp
movl %esp,%ebp
movl $30,array_len
movl $15,array_max
movl $22,max.1936
movl $0,%eax
leave
ret
.data表明以下是数据段。.global array_len表明array_len在其他文件中可见。array_max只在本文件内可见。max.1936表明只在函数内可见。由于只在函数内可见,所以可能存在多个static int max,所以这里的max被声明为max.1936。
.text段为代码段。movl $30,array_len ;movl $15,array_max; movl $22,max.1936为全局变量赋值。
指针变量
int main(void)
{
int a=22;
int *p;
p=&a;
return 0;
}
汇编代码
.text
.global main
main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
movl $22,-4(%ebp)
leal -4(%ebp),%eax
movl %eax,-8(%ebp)
movl $0,%eax
leave
ret
int a和int *p占用了8个字节。所以subl $8,%esp。
变量a的地址为-4(%ebp),所以给-4(%ebp)赋值为$22。
leal -4(%ebp),%eax取a的地址给%eax
movl %eax,-8(%ebp)将%eax的值赋值给-8(%ebp)------p。
指令 | 功能 | 描述 |
---|---|---|
leal S,D | S->D | 将S代表的地址值赋值给D |
从上文我们也可以看出变量其实代表的就是一块内存。用变量名可以轻松的使用这块内存,而如果是汇编这需要你记住每块内存的地址。