主頁 > 後端開發 > C++中的try throw catch 例外處理

C++中的try throw catch 例外處理

2020-09-21 07:21:17 後端開發

今天在開發程序中呼叫一個庫函式結果庫函式有throw操作,當前代碼沒有對throw進行捕獲操作,導致行程在main 函式中捕獲到例外導致行程crash,所以借此記錄下c++關于try,throw,catch的用法,

 

程式運行時常會碰到一些例外情況,例如:

  • 做除法的時候除數為 0;
  • 用戶輸入年齡時輸入了一個負數;
  • 用 new 運算子動態分配空間時,空間不夠導致無法分配;
  • 訪問陣列元素時,下標越界;打開檔案讀取時,檔案不存在,


這些例外情況,如果不能發現并加以處理,很可能會導致程式崩潰,

所謂“處理”,可以是給出錯誤提示資訊,然后讓程式沿一條不會出錯的路徑繼續執行;也可能是不得不結束程式,但在結束前做一些必要的作業,如將記憶體中的資料寫入檔案、關閉打開的檔案、釋放動態分配的記憶體空間等,

一發現例外情況就立即處理未必妥當,因為在一個函式執行程序中發生的例外,在有的情況下由該函式的呼叫者決定如何處理更加合適,尤其像庫函式這類提供給程式員呼叫,用以完成與具體應用無關的通用功能的函式,執行程序中貿然對例外進行處理,未必符合呼叫它的程式的需要,

此外,將例外分散在各處進行處理不利于代碼的維護,尤其是對于在不同地方發生的同一種例外,都要撰寫相同的處理代碼也是一種不必要的重復和冗余,如果能在發生各種例外時讓程式都執行到同一個地方,這個地方能夠對例外進行集中處理,則程式就會更容易撰寫、維護,

鑒于上述原因,c++ 引入了例外處理機制,其基本思想是:函式 A 在執行程序中發現例外時可以不加處理,而只是“拋出一個例外”給 A 的呼叫者,假定為函式 B,

拋出例外而不加處理會導致函式 A 立即中止,在這種情況下,函式 B 可以選擇捕獲 A 拋出的例外進行處理,也可以選擇置之不理,如果置之不理,這個例外就會被拋給 B 的呼叫者,以此類推,

如果一層層的函式都不處理例外,例外最侄訓被拋給最外層的 main 函式,main 函式應該處理例外,如果main函式也不處理例外,那么程式就會立即例外地中止,

 

C++例外處理基本語法

C++ 通過 throw 陳述句和 try...catch 陳述句實作對例外的處理,throw 陳述句的語法如下:

throw  運算式;

該陳述句拋出一個例外,例外是一個運算式,其值的型別可以是基本型別,也可以是類,

try...catch 陳述句的語法如下:

try {
    陳述句組
}
catch(例外型別) {
    例外處理代碼
}
...
catch(例外型別) {
    例外處理代碼
}

catch 可以有多個,但至少要有一個,

不妨把 try 和其后{}中的內容稱作“try塊”,把 catch 和其后{}中的內容稱作“catch塊”,

try...catch 陳述句的執行程序是:

  • 執行 try 塊中的陳述句,如果執行的程序中沒有例外拋出,那么執行完后就執行最后一個 catch 塊后面的陳述句,所有 catch 塊中的陳述句都不會被執行;
  • 如果 try 塊執行的程序中拋出了例外,那么拋出例外后立即跳轉到第一個“例外型別”和拋出的例外型別匹配的 catch 塊中執行(稱作例外被該 catch 塊“捕獲”),執行完后再跳轉到最后一個 catch 塊后面繼續執行,

例如下面的程式:

 1 #include <iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     double m ,n;
 6     cin >> m >> n;
 7     try {
 8         cout << "before dividing." << endl;
 9         if( n == 0)
10             throw -1; //拋出int型別例外
11         else
12             cout << m / n << endl;
13         cout << "after dividing." << endl;
14     }
15     catch(double d) {
16         cout << "catch(double) " << d <<  endl;
17     }
18     catch(int e) {
19         cout << "catch(int) " << e << endl;
20     }
21     cout << "finished" << endl;
22     return 0;
23 }

 

程式的運行結果如下:

9 6↙
before dividing.
1.5
after dividing.
finished

說明當 n 不為 0 時,try 塊中不會拋出例外,因此程式在 try 塊正常執行完后,越過所有的 catch 塊繼續執行,catch 塊一個也不會執行,

程式的運行結果也可能如下:

9 0↙
before dividing.
catch\(int) -1
finished

當 n 為 0 時,try 塊中會拋出一個整型例外,拋出例外后,try 塊立即停止執行,該整型例外會被型別匹配的第一個 catch 塊捕獲,即進入 catch(int e)  塊執行,該 catch 塊執行完畢后,程式繼續往后執行,直到正常結束,

如果拋出的例外沒有被 catch 塊捕獲,例如,將catch(int e),改為catch(char e),當輸入的 n 為 0 時,拋出的整型例外就沒有 catch 塊能捕獲,這個例外也就得不到處理,那么程式就會立即中止,try...catch 后面的內容都不會被執行,

能夠捕獲任何例外的 catch 陳述句

如果希望不論拋出哪種型別的例外都能捕獲,可以撰寫如下 catch 塊:

catch(...) {
    ...
}

這樣的 catch 塊能夠捕獲任何還沒有被捕獲的例外,例如下面的程式:

 1 #include <iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     double m, n;
 6     cin >> m >> n;
 7     try {
 8         cout << "before dividing." << endl;
 9         if (n == 0)
10             throw - 1;  //拋出整型例外
11         else if (m == 0)
12             throw - 1.0;  //拋出 double 型例外
13         else
14             cout << m / n << endl;
15         cout << "after dividing." << endl;
16     }
17     catch (double d) {
18         cout << "catch (double)" << d << endl;
19     }
20     catch (...) {
21         cout << "catch (...)" << endl;
22     }
23     cout << "finished" << endl;
24     return 0;
25 }

 

程式的運行結果如下:

9 0↙
before dividing.
catch (...)
finished

當 n 為 0 時,拋出的整型例外被catchy(...)捕獲,

程式的運行結果也可能如下:

0 6↙
before dividing.
catch (double) -1
finished

當 m 為 0 時,拋出一個 double 型別的例外,雖然catch (double)catch(...)都能匹配該例外,但是catch(double)是第一個能匹配的 catch 塊,因此會執行它,而不會執行catch(...)塊,

由于catch(...)能匹配任何型別的例外,它后面的 catch 塊實際上就不起作用,因此不要將它寫在其他 catch 塊前面,

例外的再拋出

如果一個函式在執行程序中拋出的例外在本函式內就被 catch 塊捕獲并處理,那么該例外就不會拋給這個函式的呼叫者(也稱為“上一層的函式”);如果例外在本函式中沒有被處理,則它就會被拋給上一層的函式,

例如下面的程式:

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 class CException
 5 {
 6 public:
 7     string msg;
 8     CException(string s) : msg(s) {}
 9 };
10 double Devide(double x, double y)
11 {
12     if (y == 0)
13         throw CException("devided by zero");
14     cout << "in Devide" << endl;
15     return x / y;
16 }
17 int CountTax(int salary)
18 {
19     try {
20         if (salary < 0)
21             throw - 1;
22         cout << "counting tax" << endl;
23     }
24     catch (int) {
25         cout << "salary < 0" << endl;
26     }
27     cout << "tax counted" << endl;
28     return salary * 0.15;
29 }
30 int main()
31 {
32     double f = 1.2;
33     try {
34         CountTax(-1);
35         f = Devide(3, 0);
36         cout << "end of try block" << endl;
37     }
38     catch (CException e) {
39         cout << e.msg << endl;
40     }
41     cout << "f = " << f << endl;
42     cout << "finished" << endl;
43     return 0;
44 }

 

程式的輸出結果如下:

salary < 0
tax counted
devided by zero
f=1.2
finished

CountTa 函式拋出例外后自行處理,這個例外就不會繼續被拋給呼叫者,即 main 函式,因此在 main 函式的 try 塊中,CountTax 之后的陳述句還能正常執行,即會執行f = Devide(3, 0);

第 35 行,Devide 函式拋出了例外卻不處理,該例外就會被拋給 Devide 函式的呼叫者,即 main 函式,拋出此例外后,Devide 函式立即結束,第 14 行不會被執行,函式也不會回傳一個值,這從第 35 行 f 的值不會被修改可以看出,

Devide 函式中拋出的例外被 main 函式中型別匹配的 catch 塊捕獲,第 38 行中的 e 物件是用復制建構式初始化的,

如果拋出的例外是派生類的物件,而 catch 塊的例外型別是基類,那么這兩者也能夠匹配,因為派生類物件也是基類物件,

雖然函式也可以通過回傳值或者傳參考的引數通知呼叫者發生了例外,但采用這種方式的話,每次呼叫函式時都要判斷是否發生了例外,這在函式被多處呼叫時比較麻煩,有了例外處理機制,可以將多處函式呼叫都寫在一個 try 塊中,任何一處呼叫發生例外都會被匹配的 catch 塊捕獲并處理,也就不需要每次呼叫后都判斷是否發生了例外,

有時,雖然在函式中對例外進行了處理,但是還是希望能夠通知呼叫者,以便讓呼叫者知道發生了例外,從而可以作進一步的處理,在 catch 塊中拋出例外可以滿足這種需要,例如:

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 int CountTax(int salary)
 5 {
 6     try {
 7         if( salary < 0 )
 8             throw string("zero salary");
 9         cout << "counting tax" << endl;
10 
11     }
12     catch (string s ) {
13         cout << "CountTax error : " << s << endl;
14         throw; //繼續拋出捕獲的例外
15     }
16     cout << "tax counted" << endl;
17     return salary * 0.15;
18 }
19 int main()
20 {
21     double f = 1.2;
22     try {
23         CountTax(-1);
24         cout << "end of try block" << endl;
25     }
26     catch(string s) {
27         cout << s << endl;
28     }
29     cout << "finished" << endl;
30     return 0;
31 }

 

程式的輸出結果如下:

CountTax error:zero salary
zero salary
finished

第 14 行的throw;沒有指明拋出什么樣的例外,因此拋出的就是 catch 塊捕獲到的例外,即 string("zero salary"),這個例外會被 main 函式中的 catch 塊捕獲,

函式的例外宣告串列

為了增強程式的可讀性和可維護性,使程式員在使用一個函式時就能看出這個函式可能會拋出哪些例外,C++ 允許在函式宣告和定義時,加上它所能拋出的例外的串列,具體寫法如下:

void func() throw (int, double, A, B, C);

void func() throw (int, double, A, B, C){...}

上面的寫法表明 func 可能拋出 int 型、double 型以及 A、B、C 三種型別的例外,例外宣告串列可以在函式宣告時寫,也可以在函式定義時寫,如果兩處都寫,則兩處應一致,

如果例外宣告串列如下撰寫:

void func() throw ();

則說明 func 函式不會拋出任何例外,

一個函式如果不交待能拋出哪些型別的例外,就可以拋出任何型別的例外,

函式如果拋出了其例外宣告串列中沒有的例外,在編譯時不會引發錯誤,但在運行時, Dev C++ 編譯出來的程式會出錯;用 Visual Studio 2010 編譯出來的程式則不會出錯,例外宣告串列不起實際作用,

C++標準例外類

C++ 標準庫中有一些類代表例外,這些類都是從 exception 類派生而來的,常用的幾個例外類如圖 1 所示,

                                                                                            

                                                                                                     圖1:常用的例外類

 

bad_typeid、bad_cast、bad_alloc、ios_base::failure、out_of_range 都是 exception 類的派生類,C++ 程式在碰到某些例外時,即使程式中沒有寫 throw 陳述句,也會自動拋出上述例外類的物件,這些例外類還都有名為 what 的成員函式,回傳字串形式的例外描述資訊,使用這些例外類需要包含頭檔案 stdexcept,

下面分別介紹以上幾個例外類,本節程式的輸出以 Visual Studio 2010為準,Dev C++ 編譯的程式輸出有所不同,

1) bad_typeid

使用 typeid 運算子時,如果其運算元是一個多型類的指標,而該指標的值為 NULL,則會拋出此例外,

2) bad_cast

在用 dynamic_cast 進行從多型基類物件(或參考)到派生類的參考的強制型別轉換時,如果轉換是不安全的,則會拋出此例外,程式示例如下:

 1 #include <iostream>
 2 #include <stdexcept>
 3 using namespace std;
 4 class Base
 5 {
 6     virtual void func() {}
 7 };
 8 class Derived : public Base
 9 {
10 public:
11     void Print() {}
12 };
13 void PrintObj(Base & b)
14 {
15     try {
16         Derived & rd = dynamic_cast <Derived &>(b);
17         //此轉換若不安全,會拋出 bad_cast 例外
18         rd.Print();
19     }
20     catch (bad_cast & e) {
21         cerr << e.what() << endl;
22     }
23 }
24 int main()
25 {
26     Base b;
27     PrintObj(b);
28     return 0;
29 }

程式的輸出結果如下:

Bad dynamic_cast!

在 PrintObj 函式中,通過 dynamic_cast 檢測 b 是否參考的是一個 Derived 物件,如果是,就呼叫其 Print 成員函式;如果不是,就拋出例外,不會呼叫 Derived::Print,

3) bad_alloc

在用 new 運算子進行動態記憶體分配時,如果沒有足夠的記憶體,則會引發此例外,程式示例如下:

 1 #include <iostream>
 2 #include <stdexcept>
 3 using namespace std;
 4 int main()
 5 {
 6     try {
 7         char * p = new char[0x7fffffff];  //無法分配這么多空間,會拋出例外
 8     }
 9     catch (bad_alloc & e)  {
10         cerr << e.what() << endl;
11     }
12     return 0;
13 }

程式的輸出結果如下:

bad allocation
ios_base::failure

在默認狀態下,輸入輸出流物件不會拋出此例外,如果用流物件的 exceptions 成員函式設定了一些標志位,則在出現打開檔案出錯、讀到輸入流的檔案尾等情況時會拋出此例外,此處不再贅述,

4) out_of_range

用 vector 或 string 的 at 成員函式根據下標訪問元素時,如果下標越界,則會拋出此例外,例如:

 1 #include <iostream>
 2 #include <stdexcept>
 3 #include <vector>
 4 #include <string>
 5 using namespace std;
 6 int main()
 7 {
 8     vector<int> v(10);
 9     try {
10         v.at(100) = 100;  //拋出 out_of_range 例外
11     }
12     catch (out_of_range & e) {
13         cerr << e.what() << endl;
14     }
15     string s = "hello";
16     try {
17         char c = s.at(100);  //拋出 out_of_range 例外
18     }
19     catch (out_of_range & e) {
20         cerr << e.what() << endl;
21     }
22     return 0;
23 }

程式的輸出結果如下:

invalid vector <T> subscript
invalid string position


如果將v.at(100)換成v[100],將s.at(100)換成s[100],程式就不會引發例外(但可能導致程式崩潰),因為 at 成員函式會檢測下標越界并拋出例外,而 operator[] 則不會,operator [] 相比 at 的好處就是不用判斷下標是否越界,因此執行速度更快,

轉自:http://c.biancheng.net/view/422.html

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/95048.html

標籤:C++

上一篇:MFC底層視窗實作

下一篇:【洛谷】P1308 統計單詞數-全AC題解(易理解

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more