为什么一个方法最好不超过4个参数,这样设计有什么好处?

摘要:简介 在很多年前的一次Code Review中,有大佬指出,方法的参数太多了,最好不要超过四个,对于当时还是萌新的我,虽然不知道什么原因,但听人劝,吃饱饭,这个习惯也就传递下来了,直到参加工作很多年后,才明白这其中的缘由。 调用协定 在计算
简介 在很多年前的一次Code Review中,有大佬指出,方法的参数太多了,最好不要超过四个,对于当时还是萌新的我,虽然不知道什么原因,但听人劝,吃饱饭,这个习惯也就传递下来了,直到参加工作很多年后,才明白这其中的缘由。 调用协定 在计算机编程中,调用协定(Calling Convention)是一套关于方法/函数被调用时参数传递方式,栈由谁清理和寄存器如何使用的规范。 参数传递方式 寄存器传递:将参数存入CPU寄存器,速度最快。 栈传递:将参数压入调用栈,再依次从栈中取出,速度最慢 混合传递:前N个参数用寄存器,剩余参数用栈,速度适中 栈由谁清理 Caller清理:调用函数后由调用方负责恢复栈指针(如C/C++的__cdecl)。 Callee清理:被调用函数返回前自行清理栈(如x64的默认协定)。 寄存器如何使用 易变寄存器(Volatile Registers):函数调用时可能被修改的寄存器(如x64的RAX、RCX、RDX),调用方需自行保存这些寄存器的值。 非易变寄存器(Non-Volatile Registers):函数必须保存并恢复的寄存器(如x64的RBX、RBP、R12-R15)。 x86架构混乱的调用协定 x86架构发展较早,因此调用协定野蛮生长,有多种调用协定 协定名称 参数传递方式 栈清理 适用场景 __cdecl 通过栈传递(右→左) 调用者清理栈 C/C++默认,支持可变参数 __stdcall 通过栈传递(右→左) 被调用者清理栈 Windows API(如Win32) __fastcall 前两个参数通过寄存器,剩余通过栈(右→左) 被调用者清理栈 高性能场景 __thiscall this指针通过寄存器, 剩余通过栈(右→左) 被调用者清理栈 C++类成员函数 眼见为实 可以看到,cdecl,stdcall是通过压栈的方式将参数压入栈中,而fastcall直接赋值给寄存器,并无压栈操作 点击查看代码 #include <iostream> int __cdecl cdecl_add(int a, int b) { return a + b; } int __stdcall stdcall_add(int a, int b) { return a + b; } int __fastcall fastcall_add(int a, int b) { return a + b; } class Calculator { public: int __thiscall thiscall_add(int b) { return this->a + b; } int a; }; int main() { int a = 10, b = 5; int cdecl_add_value = cdecl_add(a, b); int stdcall_add_value = stdcall_add(a, b); int fastcall_add_value = fastcall_add(a, b); Calculator calc; calc.a = 10; int thiscall_add_value = calc.thiscall_add(5); } x64的大一统 而在x64架构下,为了解决割裂的调用协定,windows与linux实现了统一。
阅读全文