在C语言中,函数通过返回值和参数与调用者交换信息,对参数理解和使用的正确与否,直接影响到函数功能能否正确实现;
函数参数自身占用的存储单元在堆栈中分配,入口参数指向的数值或者地址在函数入口处拷贝到 堆栈区中,因此对函数参数所在存储单元的直接修改不会作用到函数之外,而对参数存储单元中 存放的地址指向的存储空间的修改,则会在函数之外其作用;
调用者在进行函数调用之前,必须事先申明被调用函数的原型,包括返回值类型和参数类型;
C标准没有规定参数入栈计算顺序的问题,参数的计算顺序是不确定的,这个我们需要牢牢记住。
CHAR * GetMemory(CHAR *p)
{
/* 申请内存 */
p = (CHAR *)malloc(100);
return p;
}
VOID Test(void)
{
CHAR *str = NULL;
If (NULL != GetMemory(str))
{
strcpy(str, "hello world");
printf(str);
}
return;
}
CHAR* GetMemory(CHAR **p)
{
/* 申请内存 */
*p = (CHAR *)malloc(100);
return *p;
}
VOID Test(void)
{
CHAR *str = NULL;
If (NULL != GetMemory(&str))
{
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
}
return;
}
环境VC,已知VC编译后的代码参数从右向左入栈。
#include <stdio.h>
int main(void)
{
char xx, yy;
char acArray[10]="aceg";
char *p0 = acArray;
char *p1 = acArray;
printf("%d,%d\n", *p0, *p0++);
xx = *p1++;
yy = *p1;
printf(“xx %d, yy %d\n”, xx, yy);
return 0;
}
分析一下:
1. 第一条printf,由于右边的参数先入栈,于是应该先把*p0 push进去,然后++,再把*p0 push进去,输出的是acArray[1], acArray[0](也就是 99,97)
2. 对于xx, yy 自然没什么好说的了,就是 xx = acArray[0]; yy = acArray[1];
可是看看输出的结果呢:
97,97
xx 99, yy101
Press any key to continue
我也是纳闷了半天,前边push的都是acArray[0],那个++根本就没有起作用!??理解不了只好看看它的汇编:
10: printf("%d,%d\n", *p0, *p0++);
0040B7ED mov edx,dword ptr [ebp-18h] ; ebp-18h 就是p0的地址(里边存着数组的起始地址)不信你可以自己数一下,相当于把acArray放到edx。
0040B7F0 movsx eax,byte ptr [edx] ;第一个元素放到eax
0040B7F3 mov dword ptr [ebp-20h],eax ; 临时变量打了一圈,就是没有给你加1
0040B7F6 mov ecx,dword ptr [ebp-20h]
0040B7F9 push ecx ;就是我们的 *p0++
0040B7FA mov edx,dword ptr [ebp-18h] ;跟前边一模一样,取了数组的第一个
0040B7FD movsx eax,byte ptr [edx]
0040B800 push eax ; 这里是 *p0
0040B801 push offset string "b:%p\n" (00420024) ;push 格式化字符串起始地址
0040B806 mov ecx,dword ptr [ebp-18h] ;把acArray[0] load到ecx
0040B809 add ecx,1 ; 这里才++
0040B80C mov dword ptr [ebp-18h],ecx ;++完了再放回去
0040B80F call printf (004010c0) ; 调用printf
0040B814 add esp,0Ch ; 这个用来恢复栈空间到调用printf前的样子,push了三次所以只需要把esp + 12栈顶就回来了。
编译器实在是太聪明了吧!不过不死心,编译release版,运行:
99,97
xx 97, yy 99
Press any key to continue
奇怪了,同样的代码这时候结果却大不一样。真正的做到了*p0++之后就把指针作了加一。
只好再看汇编:
真的是不确定!
函数参数自身占用的存储单元在堆栈中分配,入口参数指向的数值或者地址在函数入口处拷贝到 堆栈区中,因此对函数参数所在存储单元的直接修改不会作用到函数之外,而对参数存储单元中 存放的地址指向的存储空间的修改,则会在函数之外其作用;
调用者在进行函数调用之前,必须事先申明被调用函数的原型,包括返回值类型和参数类型;
C标准没有规定参数入栈计算顺序的问题,参数的计算顺序是不确定的,这个我们需要牢牢记住。
CHAR * GetMemory(CHAR *p)
{
/* 申请内存 */
p = (CHAR *)malloc(100);
return p;
}
VOID Test(void)
{
CHAR *str = NULL;
If (NULL != GetMemory(str))
{
strcpy(str, "hello world");
printf(str);
}
return;
}
CHAR* GetMemory(CHAR **p)
{
/* 申请内存 */
*p = (CHAR *)malloc(100);
return *p;
}
VOID Test(void)
{
CHAR *str = NULL;
If (NULL != GetMemory(&str))
{
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
}
return;
}
环境VC,已知VC编译后的代码参数从右向左入栈。
#include <stdio.h>
int main(void)
{
char xx, yy;
char acArray[10]="aceg";
char *p0 = acArray;
char *p1 = acArray;
printf("%d,%d\n", *p0, *p0++);
xx = *p1++;
yy = *p1;
printf(“xx %d, yy %d\n”, xx, yy);
return 0;
}
分析一下:
1. 第一条printf,由于右边的参数先入栈,于是应该先把*p0 push进去,然后++,再把*p0 push进去,输出的是acArray[1], acArray[0](也就是 99,97)
2. 对于xx, yy 自然没什么好说的了,就是 xx = acArray[0]; yy = acArray[1];
可是看看输出的结果呢:
97,97
xx 99, yy101
Press any key to continue
我也是纳闷了半天,前边push的都是acArray[0],那个++根本就没有起作用!??理解不了只好看看它的汇编:
10: printf("%d,%d\n", *p0, *p0++);
0040B7ED mov edx,dword ptr [ebp-18h] ; ebp-18h 就是p0的地址(里边存着数组的起始地址)不信你可以自己数一下,相当于把acArray放到edx。
0040B7F0 movsx eax,byte ptr [edx] ;第一个元素放到eax
0040B7F3 mov dword ptr [ebp-20h],eax ; 临时变量打了一圈,就是没有给你加1
0040B7F6 mov ecx,dword ptr [ebp-20h]
0040B7F9 push ecx ;就是我们的 *p0++
0040B7FA mov edx,dword ptr [ebp-18h] ;跟前边一模一样,取了数组的第一个
0040B7FD movsx eax,byte ptr [edx]
0040B800 push eax ; 这里是 *p0
0040B801 push offset string "b:%p\n" (00420024) ;push 格式化字符串起始地址
0040B806 mov ecx,dword ptr [ebp-18h] ;把acArray[0] load到ecx
0040B809 add ecx,1 ; 这里才++
0040B80C mov dword ptr [ebp-18h],ecx ;++完了再放回去
0040B80F call printf (004010c0) ; 调用printf
0040B814 add esp,0Ch ; 这个用来恢复栈空间到调用printf前的样子,push了三次所以只需要把esp + 12栈顶就回来了。
编译器实在是太聪明了吧!不过不死心,编译release版,运行:
99,97
xx 97, yy 99
Press any key to continue
奇怪了,同样的代码这时候结果却大不一样。真正的做到了*p0++之后就把指针作了加一。
只好再看汇编:
真的是不确定!