日韩欧美人妻无码精品白浆,www.大香蕉久久网,狠狠的日狠狠的操,日本好好热在线观看

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

為什么說方法的參數(shù)最好不要超過4個?

freeflydom
2025年7月2日 8:21 本文熱度 91

簡介

在很多年前的一次Code Review中,有大佬指出,方法的參數(shù)太多了,最好不要超過四個,對于當(dāng)時還是萌新的我,雖然不知道什么原因,但聽人勸,吃飽飯,這個習(xí)慣也就傳遞下來了,直到參加工作很多年后,才明白這其中的緣由。

調(diào)用協(xié)定

在計算機(jī)編程中,調(diào)用協(xié)定(Calling Convention)是一套關(guān)于方法/函數(shù)被調(diào)用時參數(shù)傳遞方式棧由誰清理寄存器如何使用的規(guī)范。

  1. 參數(shù)傳遞方式
  • 寄存器傳遞:將參數(shù)存入CPU寄存器,速度最快。
  • 棧傳遞:將參數(shù)壓入調(diào)用棧,再依次從棧中取出,速度最慢
  • 混合傳遞:前N個參數(shù)用寄存器,剩余參數(shù)用棧,速度適中
  1. 棧由誰清理
  • Caller清理:調(diào)用函數(shù)后由調(diào)用方負(fù)責(zé)恢復(fù)棧指針(如C/C++的__cdecl)。
  • Callee清理:被調(diào)用函數(shù)返回前自行清理棧(如x64的默認(rèn)協(xié)定)。
  1. 寄存器如何使用
  • 易變寄存器(Volatile Registers):函數(shù)調(diào)用時可能被修改的寄存器(如x64的RAX、RCXRDX),調(diào)用方需自行保存這些寄存器的值。
  • 非易變寄存器(Non-Volatile Registers):函數(shù)必須保存并恢復(fù)的寄存器(如x64的RBXRBP、R12-R15)。

x86架構(gòu)混亂的調(diào)用協(xié)定

x86架構(gòu)發(fā)展較早,因此調(diào)用協(xié)定野蠻生長,有多種調(diào)用協(xié)定

協(xié)定名稱參數(shù)傳遞方式棧清理適用場景
__cdecl通過棧傳遞(右→左)調(diào)用者清理棧C/C++默認(rèn),支持可變參數(shù)
__stdcall通過棧傳遞(右→左)被調(diào)用者清理棧Windows API(如Win32)
__fastcall前兩個參數(shù)通過寄存器,剩余通過棧(右→左)被調(diào)用者清理棧高性能場景
__thiscallthis指針通過寄存器, 剩余通過棧(右→左)被調(diào)用者清理棧C++類成員函數(shù)

眼見為實

可以看到,cdecl,stdcall是通過壓棧的方式將參數(shù)壓入棧中,而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的大一統(tǒng)

而在x64架構(gòu)下,為了解決割裂的調(diào)用協(xié)定,windows與linux實現(xiàn)了統(tǒng)一。

協(xié)定名稱參數(shù)傳遞方式棧清理適用場景
MS x64前4個參數(shù)通過寄存器,剩余通過棧(左→右)被調(diào)用者清理棧Windows x64程序
System V AMD64前6個參數(shù)通過寄存器,剩余通過棧(左→右)被調(diào)用者清理棧Unix/Linux x64程序

眼見為實

linux下暫無圖(因為我懶),大概就是這意思,自行腦補

點擊查看代碼
#include <stdio.h>
int add(int a, int b, int c, int d, int e) {
    return a + b + c + d + e;
}
int main() {
    int result = add(1, 2, 3, 4, 5);
    return 0;
}

C#中使用哪種調(diào)用協(xié)定?

C#在x86下,有自己獨特的調(diào)用協(xié)定

協(xié)定名稱參數(shù)傳遞方式棧清理適用場景
Standard前兩個參數(shù)通過寄存器,剩余通過棧(左→右)被調(diào)用者清理棧C#靜態(tài)方法
HasThis前兩個參數(shù)通過寄存器(第一個為This),剩余通過棧(左→右)被調(diào)用者清理棧C#實例方法

在x64形成實現(xiàn)統(tǒng)一,與操作系統(tǒng)保持一致

眼見為實



注意寄存器與棧是兩片獨立運行的區(qū)域,光從匯編代碼,很容易陷入誤區(qū),就拿上圖來說,從上往下閱讀匯編,你會發(fā)現(xiàn)參數(shù)傳遞的順序是30(1Eh),40(28h),50(32h),10(0Ah),20(14h)。明顯不對,這是因為一個是寄存器,一個是線程棧,這是兩個不相關(guān)的區(qū)域,誰前誰后都不違反從左到右的規(guī)定。不能死腦筋,寄存器與棧之間是存在位置無關(guān)性的。

/*這種順序也是正確的,寄存器是寄存器,棧是棧,匯編的順序不影響他們的位置無關(guān)性,因為是兩片獨立運行的區(qū)域*/
push 1Eh
mov ecx,0Ah
push 28h
mov edx,14h
push 32h
點擊查看代碼
    internal class Program
    {
        static void Main(string[] args)
        {
            var t = new Test();
            var sum = t.Add(10, 20, 30, 40, 50);
            var sum2 = Test.StaticAdd(10, 20, 30, 40, 50);
            Console.ReadKey();
        }
    }
    public class Test
    {
        public int Add(int a, int b, int c, int d, int e)
        {
            var sum = a + b + c + d + e;
            return sum;
        }
        public static int StaticAdd(int a, int b, int c, int d, int e)
        {
            var sum = a + b + c + d + e;
            return sum;
        }
    }

結(jié)論

可以看到,在Windows x64下,如果方法的參數(shù)<=4 那么就就完全避免了棧傳遞的開銷,實現(xiàn)性能最佳化。

在linux下,參數(shù)為<=6,根據(jù)木桶效應(yīng),取4為最佳。

當(dāng)然,此文不是讓你嚴(yán)格遵守此規(guī)則,隨著CPU性能的發(fā)展,在微服務(wù)集群大行其道的今天。這點性能差距可以忽略不計,權(quán)當(dāng)飯后消遣,補充冷知識,好讓你在未來的Code Review中,沒活硬整.

點擊查看代碼
    internal class Program
    {
        static void Main(string[] args)
        {
            ParameterPassingBenchmark.Run();
        }
    }
    public class ParameterPassingBenchmark
    {
        private const int WarmupIterations = 100000;
        private const int BenchmarkIterations = 10000000;
        private const int BatchSize = 1000; // 批量調(diào)用次數(shù),提高測量精度
        private static readonly Random _random = new Random(42);
        // x64平臺前4個參數(shù)通過寄存器傳遞
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
        public static int Register4Params(int a, int b, int c, int d) => a + b + c + d;
        // 第5個參數(shù)通過棧傳遞
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
        public static int Stack1Param(int a, int b, int c, int d, int e) => a + b + c + d + e;
        // 第5-8個參數(shù)通過棧傳遞
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
        public static int Stack4Params(int a, int b, int c, int d, int e, int f, int g, int h)
            => a + b + c + d + e + f + g + h;
        public static void Run()
        {
            Console.WriteLine($"參數(shù)傳遞性能測試 - 預(yù)熱: {WarmupIterations:N0}, 測試: {BenchmarkIterations:N0} 次");
            Console.WriteLine("----------------------------------------------------------------");
            // 生成隨機(jī)輸入數(shù)據(jù)以避免優(yōu)化
            var inputData = GenerateInputData();
            // 預(yù)熱
            Warmup(inputData);
            // 測試
            var reg4Time = Measure(() => Register4ParamsTest(inputData));
            var stack1Time = Measure(() => Stack1ParamTest(inputData));
            var stack4Time = Measure(() => Stack4ParamsTest(inputData));
            // 輸出結(jié)果
            Console.WriteLine("\n===== 測試結(jié)果 =====");
            Console.WriteLine($"4寄存器參數(shù): {reg4Time,12:N2} ns/次");
            Console.WriteLine($"4寄存器+1棧參數(shù): {stack1Time,10:N2} ns/次 ({((double)stack1Time / reg4Time - 1) * 100:F1}% 性能下降)");
            Console.WriteLine($"4寄存器+4棧參數(shù): {stack4Time,10:N2} ns/次 ({((double)stack4Time / reg4Time - 1) * 100:F1}% 性能下降)");
        }
        private static (int[], int[], int[]) GenerateInputData()
        {
            var data4 = new int[BenchmarkIterations * 4];
            var data5 = new int[BenchmarkIterations * 5];
            var data8 = new int[BenchmarkIterations * 8];
            for (int i = 0; i < BenchmarkIterations; i++)
            {
                for (int j = 0; j < 4; j++) data4[i * 4 + j] = _random.Next();
                for (int j = 0; j < 5; j++) data5[i * 5 + j] = _random.Next();
                for (int j = 0; j < 8; j++) data8[i * 8 + j] = _random.Next();
            }
            return (data4, data5, data8);
        }
        private static void Warmup((int[], int[], int[]) inputData)
        {
            Console.Write("預(yù)熱中...");
            var (data4, data5, data8) = inputData;
            for (int i = 0; i < WarmupIterations; i++)
            {
                Register4Params(data4[i * 4], data4[i * 4 + 1], data4[i * 4 + 2], data4[i * 4 + 3]);
                Stack1Param(data5[i * 5], data5[i * 5 + 1], data5[i * 5 + 2], data5[i * 5 + 3], data5[i * 5 + 4]);
                Stack4Params(data8[i * 8], data8[i * 8 + 1], data8[i * 8 + 2], data8[i * 8 + 3],
                            data8[i * 8 + 4], data8[i * 8 + 5], data8[i * 8 + 6], data8[i * 8 + 7]);
            }
            Console.WriteLine("完成");
        }
        private static long Measure(Func<long> testMethod)
        {
            // 強(qiáng)制GC并等待完成
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            // 冷啟動
            testMethod();
            // 實際測量
            var stopwatch = Stopwatch.StartNew();
            long result = testMethod();
            stopwatch.Stop();
            // 使用結(jié)果以避免被優(yōu)化掉
            if (result == 0) Console.WriteLine("警告: 結(jié)果為0,可能存在優(yōu)化問題");
            // 計算平均時間(納秒)
            long totalNs = stopwatch.ElapsedTicks * 10000000L / Stopwatch.Frequency;
            return totalNs / (BenchmarkIterations / BatchSize); // 除以實際調(diào)用批次
        }
        private static long Register4ParamsTest((int[], int[], int[]) inputData)
        {
            var (data4, _, _) = inputData;
            long sum = 0;
            int index = 0;
            for (int i = 0; i < BenchmarkIterations / BatchSize; i++)
            {
                // 批量調(diào)用以提高測量精度
                for (int j = 0; j < BatchSize; j++)
                {
                    sum += Register4Params(
                        data4[index++],
                        data4[index++],
                        data4[index++],
                        data4[index++]
                    );
                }
            }
            return sum;
        }
        private static long Stack1ParamTest((int[], int[], int[]) inputData)
        {
            var (_, data5, _) = inputData;
            long sum = 0;
            int index = 0;
            for (int i = 0; i < BenchmarkIterations / BatchSize; i++)
            {
                // 批量調(diào)用以提高測量精度
                for (int j = 0; j < BatchSize; j++)
                {
                    sum += Stack1Param(
                        data5[index++],
                        data5[index++],
                        data5[index++],
                        data5[index++],
                        data5[index++]
                    );
                }
            }
            return sum;
        }
        private static long Stack4ParamsTest((int[], int[], int[]) inputData)
        {
            var (_, _, data8) = inputData;
            long sum = 0;
            int index = 0;
            for (int i = 0; i < BenchmarkIterations / BatchSize; i++)
            {
                // 批量調(diào)用以提高測量精度
                for (int j = 0; j < BatchSize; j++)
                {
                    sum += Stack4Params(
                        data8[index++],
                        data8[index++],
                        data8[index++],
                        data8[index++],
                        data8[index++],
                        data8[index++],
                        data8[index++],
                        data8[index++]
                    );
                }
            }
            return sum;
        }
    }

轉(zhuǎn)自https://www.cnblogs.com/lmy5215006/p/18919081


該文章在 2025/7/2 8:21:37 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調(diào)度、堆場、車隊、財務(wù)費用、相關(guān)報表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點,圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務(wù)都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

有码美女在线| 最新国产综合精品| 国产精品性感美女教师自慰| 日本韩国淫秽视频网站| 亚洲一区二区三区 中文字幕| 噜噜噜噜噜久久久久久1526| 粉嫩小穴久久久久久久| 久久久這里有精品| 亚洲综合色婷| 免费成人电影熟妇毛片| 欧美激情影院综合| 97国产精品自拍| 欧美亚洲色片| 亚洲一区二区三区骚逼| av销魂美女| 99精品毛片| 日韩av一区二区三区四区| 国产图片一区二区三区| 国产一区二区三区高清日韩麻豆| 国产AV午夜场| 亚洲+欧美+韩日+精品| 综合AV中文字幕| 51一区二区| 国产欧美日韩精品播放| 99精品丰满人妻无xxx| 国产精品久久久久久久AV三级 | 欧美日韩国产人妻不卡一区二区| 在线大香蕉小说观看| 国产精品久久午夜伦理| 嫩香蕉AV| 日韩丝袜AV在线播放| 图片视频日韩无码电影一区二区三区| 校园纯色AV| 欧美午夜熟女| 日本无码免费三a级毛片| 又大又粗又猛又爽的视频| 2019精品视频久久久| 国产成人精品欧| 亚洲视频在线一区| 国际亚洲a久久久久久| 亚洲 成人 不卡|