1 函数参数的本质
1.1 函数参数的本质
函数参数的本质如下:
- 函数参数在本质上与局部变量相同在栈上分配空间。
- 函数参数的初始值是函数调用时的实参值。

2 函数参数的求值顺序
2.1 顺序点的概念
顺序点是C语言中变量修改的最晚时机。
程序中的顺序点:
- 程序中存在一定的顺序点。
- 顺序点指的是执行过程中修改变量值的最晚时刻。
- 在程序到达顺序点的时候,之前所做的一切内存操作必须完成。
C语言中的顺序点:
- 每个完整表达式结束时,即分号处。
- &&,||,?:以及逗号表达式的每个参数计算后。
- 函数调用时所有实参求值完成后(进入函数体之前)。

输出结果:6(gcc、bcc、vc)
分析:首先将k的值取道寄存器中去,然后再从内存中把k的值取出来和寄存器中的值进行相加,将值保存到k中去,此时悬挂了两个++操作。然后进行两次++操作,所以此时的k为6。
编程实验:程序中的顺序点
#include <stdio.h>
int main()
{
int k = 2;
int a = 1;
k = k++ + k++;
printf("k = %d\n", k); // 6
if( a-- && a )
{
printf("a = %d\n", a); // 不打印
}
return 0;
}
2.2 函数参数的求值顺序分析
函数参数的求值顺序依赖于编译器的实现。

gcc: 2 1 3(最后一个为k的值)
bcc:2 1 3
vc: 1 1 3(跟顺序点有关,假设从第二个参数开始求值,首先从内存中取出k的值为1,此时的++操作并没有进,而是处于悬挂状态,所以第二个参数的值为1。然后对第一个参数进行求值,从内存中取出k的值为1,++操作仍然悬挂着,所以此时第一个参数的值也为1。由于顺序点存在于函数调用时所有实参求值完成后,即进入函数体前,所以此时必须进行修改内存的操作,执行两个++操作,使得此时的k的值变成了3)。
注意:C语言中只规定了必须将参数的值计算出来再进行函数调用,并没有规定参数的求值顺序。可类比到操作符中,操作符的求值顺序也是不固定的,依赖于编译器的实现。
3 函数参数的入栈顺序
3.1 调用约定
当函数调用发生时:
- 参数会传递给被调用的函数。
- 而返回值会被返回给函数调用者。
调用约定描述参数如何传递到栈中以及栈的维护方式:
- 参数传递顺序。
- 调用栈清理。
当主函数调用第三方库时,需要考虑调用约定是否一致。
关于调用约定:
- 调用约定是预定义的,可理解为调用协议。
- 调用约定通常用于库调用和库开发的时候:
- 从右到左依次入栈:_stdcall,_cdecl(C语言默认是这个),_thiscall;
- 从左到右依次入栈:_pascal, _fastcall。

参考资料:
403

被折叠的 条评论
为什么被折叠?



