C语言-参数-返回值-局部变量-数组:
返回值
char Funtion(){
//10000行代码
return 10;
}
//c语言角度:这里定义的函数类型是char(字符型),表示我将返回的的数据是一个字符型数据
//汇编语言角度:我创建了个函数,函数的返回值是一个字节
int main(){
char i = Funtion();
return 0;
}
//因为我们设置的是返回一个字符型返回值,所以对应的用一个字符型变量去接收
对应的反汇编:
call Funtion
......//保存现场,提升堆栈等
mov al,0Ah //0Ah对应的二进制就是10,意思就是向寄存器al中存入10这个数。
......//恢复现场,恢复堆栈等
mov byte ptr [ebp-4],al
这里的类型可以是任意的,char,short,int.long,long long在计算机看来只是大小不同而已。所以在正向编程的时候,只要不用小的数据类型去接收一个大的数据,程序就还是正常运行的。
关于这个用更小的数据类型去接收一个超过其容量的返回值,它也不会有错误,只是在传输数据的时候,它只会取返回值的低位放入我们声明的数据变量中。
特别注意的是long long类型的数据,long long类型是8个字节也就是16位二进制,在传输的时候一个寄存器eax是肯定存不下的了,所以它用到了两个寄存器eax和edx,各8位就刚好16位。eax中存低八位,edx中存高八位。
参数传递的本质
将上层函数的变量或者是表达式的值,通过寄存器或堆栈传递给下层函数。
参数在传递的过程中,传输的都是四个字节。与设置的参数的数据类型是没有关系的。
int ADD(int x){
x = x+1;
}
int main(){
int x = 2;
ADD(x);
printf("%d",x);
}
//最后输出的x是多少?
//正向学习的时候,这个形参和实参比较绕,但是学会反汇编之后。妈妈再也不用担心我学习!!!
函数创建时分配的空间大小
在创建函数时,编译器会有一个默认的大小给到堆栈,在这个默认大小的基础下,根据函数中设置的局部变量的多少来扩充堆栈的大小(无论你是创建什么类型的局部变量,它都会单独给分配 一个堆栈地址空间。一个堆栈地址空间就是4个字节)
参数和局部变量都是堆栈中的值。区别就是内存分配的时间。参数是在函数调用前在堆栈中存储的值,局部变量是在调用函数时在堆栈中存储的值。
赋值语句的本质
复制的本质就是将值存储到变量中的过程。
数组的本质
(这里是静态数组)在堆栈中连续的存储一系列的值。在创建的时候,计算机要知道数组多大才好分配空间。
int ADD(x,y){
return x+y;
}
void Function(){
int x = 1;
int y = 2;
int r;
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
r = arr[1];
r = arr[x];
r = arr[x+y];
r = arr[x*2+y];
r = arr[arr[1]+arr[2]];
r = arr[ADD(1,2)];
r = arr[100];
}
int main(){
Function();
return 0;
}
//看反汇编,了解值的传递
数组越界(arr[100])。在编译时是可以执行的,但是它找的对应位置就是不确定的。但是我觉得这有很大的开发潜力。
桶排序
创建一个数组,数组大小是待排序数中的最大值。根据数的值到对应数组位置进行加一操作,最后通过数组把排列数对应着打印出来。(排列数映射到对应数组的下标)
多维数组
和一维数组的反汇编一样的。
//多维数组
int arr[3][4]={
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
}
//一维数组
int brr[12]={1,2,3,4,5,6,7,8,9,10,11,12}
多维数组会 3乘4来得出这个多维数组需要的空间大小,在堆栈中发分配方式和一维数组一样。(CPU没有多维的概念)
对应反汇编代码
对比这两个反汇编的不同处,我们应该着重关注:
①、堆栈分配的大小。因为在函数中只声明了两个数组作为局部变量,且数组的大小都一样(3*4=12),所以CPU分配的堆栈空间也是一样的。
②、数据放在堆栈的位置。因为两个数组我们设置的数据顺序都是一样的,所以连存放的位置都是一样的。
编译器创建数组时的小特点:
1、自动补零。当我发现我的数组还有空余时,我会把空挡补零。
2、自动分组。我在创建多维数组时,我可以不确定组数,也可以不确定每组个数。(两者需要确定一个)在确定好一个之后,编译器会自动分组,不足补零。
3、多维数组的查找方法:arr[1] [3] = arr[1*个数+3]