参数、返回值、局部变量、数组分析

1.返回值的传递
各种类型返回值传出来的方式:
    1、char类型的返回值    ->寄存器al
    2、short 类型的返回值    ->寄存器ax
    3、int 类型的返回值    ->寄存器eax
 
如果是long long 则将低位保存在eax,将高位保存在edx;
//vc用__int64表示long long
__int64 fun(){
    return 0x1234567890;
}
 
int main(int argc, char* argv[])
{    
    __int64 a = fun();
    return 0;
}
在函数中返回值保存:
在函数外面取出返回值:
    
 
总之:
    int、char、long、数组等变量类型本质上的区别只是到底能存多少位的数,也就是容量的区别;
 
2.参数传递的本质
参数传递有两种方式:1】寄存器;2】堆栈;
 
不同类型的参数传递时,通常会转换成本机尺寸来传递;
例如32位机中char类型的参数:虽然char是1个字节,但传递到栈中时按4个自己来保存;
情况1:
void fun(char x, char y){
 
}
 
int main(int argc, char* argv[])
{    
    fun(1,2);
    return 0;
}
参数入栈前:
参数入栈后:
 
情况2:
void fun(char x, char y){
 
}
 
int main(int argc, char* argv[])
{    
    char a=1,b=2;
    fun(a,b);
    return 0;
}
 
可以看出:
    两个char类型的参数,入栈后栈顶减少8个字节;
    也就是参数虽然定义的是一个字节,但是按4个字节传递的;
原因:                                                                        
    1、本机尺寸:如果本机是32位的,那么对32位的数据支持最好,如果是64位的,那么对64位的支持最好.                                                                    
    2、编译器遵守了这个规则:char类型或者short类型的参数不但没有节省空间,反而浪费了多余的操作.   
    就像一个人一步可以走1米,不会强行将一步分成四小步0.25米一样;                             
结论:整数类型的参数,一律使用int类型
    因为其它类型如short、char非但不能节省空间,反而还要转换;
 
                                
2)参数传递的本质:将上层函数的变量,或者表达式的值“复制一份”,传递给下层函数.  
例如:下面的函数输出结果为2;
    
原因:
    main函数中的x作为参数是实际上是复制了一份,并界保存在fun函数的ebp+8中;
    fun函数的作用是将参数ebp+8取出来加一后再次存入ebp+8;
    main函数的x是局部变量,存放在main的ebp-4中;上面的操作对main的局部变量毫无影响;
反汇编:
main函数:
fun函数:
 
3.局部变量
    1、小于32位的局部变量,空间在分配时,按32位分配.                                        
    2、使用时按实际的宽度使用.                                        
    3、不要定义char/short类型的局部变量.                                        
    4、参数与局部变量没有本质区别,都是局部变量,都在栈中分配.                                        
    5、完全可以把参数当初局部变量使用
也就是说,局部变量和参数对一个函数来说,无非就是在堆栈中放在ebp-4之后和ebp+8之前的区别;
 
4.赋值的本质
就是将某个值存储到变量的过程;
例如:以下都是赋值语句
    int x = 1;    
    int y = 2;    
    int z = 3;    
    int r = 1*2+3;    
    int r = 1*(2+3);
    int r = x + y;
    int r = Add(x,y)
 
5.数组
一组相同类型的变量,为了方便读写,采用另外一种表示形式.
比如:需要10个int型变量,为了方便,可以定义一个长度为10的int数组;
 
1)数组声明时
数组在声明的时候,必须用常量来指明长度,不能使用变量
也就是说下面的方式是错误的:
int x=10;
int arr[x]={0,1,2};
从编译器的角度来看,如果无法给定确切的长度,将不知道给数组分配多少空间,而变量的值是不确定的;
正确的数组声明方式:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
 
2)数组使用时
    1、数组在使用时,可以通过变量来定位数据.                                                        
    2、数组定位时,可以超过数组的长度,编译不会有错,但读取的数据是错的
下面的代码都可以通过编译:
void Function()                
{                
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};            
                
    int x = 1;            
    int y = 2;            
    int r ;
                        
    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)];            
    int a5 = arr[100];            
}
 
3)数组空间分配
如果是普通局部变量,在32位机中,不足4字节的分配4个字节的空间;
数组分配空间的规则:
    按数组的宽度来分配空间;
    以4个字节为单位来分配;
例如:3个元素的char数组分配4个字节;
    4个元素的char数组同样分配4个字节;
    5个元素的char数组分配8个字节;
 
3个元素的char数组:
 
 
 

猜你喜欢

转载自www.cnblogs.com/ShiningArmor/p/11571137.html