[源碼下載]
作者:webabcd
介紹
不可或缺 Windows Native 之 C 語言
示例
cFunction.h
#ifndef _MYHEAD_FUNCTION_ #define _MYHEAD_FUNCTION_ #ifdef __cplusplus extern "C" #endif // 函數聲明 // 像這種在 .h 中聲明的函數,如果想被外部文件調用的話,則外部文件不用再聲明即可調用 char *demo_cFunction(); long recursion(int n); void update(int ary[], int aryLength); // 也可以將上面的函數聲明寫成下面這種形式,像這種只有參數類型,沒有參數名稱的函數聲明稱之為函數原型(function prototype) // void update(int[], int); void demo_variable1(); void demo_variable2(); void demo_params(); // 加上 static 關鍵字就是內部函數,僅能在當前文件使用;在不同的文件中如果有同名的內部函數,則他們互不干擾 static void cFunction_demo1(); // 加上 extern 關鍵字就是外部函數,可被其他文件調用 extern void cFunction_demo2(); // 如果既無 static 也無 extern,則默認為 extern void cFunction_demo3(); #endif
cFunction.c
/* * 函數 * * * 1、從變量的作用域(scope)角度來分,可以分為全局變量(外部變量)和局部變量 * 2、從變量的生存期角度來分,可以分為靜態存儲方式和動態存儲方式 * * * argument - 實參 * parameter - 形參 */ #include "pch.h" #include "cFunction.h" #include "cHelper.h" // 全局變量(亦稱外部變量),作用域(scope)是整個源程序 int global01 = 100; // 像這種定義在 .c 中的函數(無論在 .c 文件中有無函數聲明),如果想被外部文件調用的話,則外部文件在調用之前需要先聲明 void function0() { ; } char *demo_cFunction() { // 函數定義在之前,則不用聲明也可以調用(同一文件);函數定義在之後,則必須先聲明才可以調用 function0(); // 以下為無參數無返回值的函數聲明(declare),其同 void demo_cFunction1(); void function1(void); // 以下為有參數有返回值的函數聲明 int function2(int a, int b); // 也可以將上面的函數聲明寫成下面這種形式,像這種只有參數類型,沒有參數名稱的函數聲明稱之為函數原型(function prototype) // int demo_cFunction2(int, int); // 無參數,無返回值函數演示 function1(); // 有參數,有返回值函數演示 int a = 1, b = 1; // 這裡的 a 和 b 是實參 int x = function2(a, b); // 函數遞歸 long y = recursion(100); // 結果:5050 // 向函數傳遞數組類型的演示 // 之前說過 ary 是數組的首地址,也就是說傳遞過去的是指針,也就是說實參和形參其實指向的是一個地方,相當於引用類型 int ary[] = {0, 1, 2, 3, 4 }; update(ary, 5); // 數組 ary 被更新了 // 局部變量和全局變量的演示 demo_variable1(); // 變量存儲方式的演示 demo_variable2(); // 參數不定的函數(可變參數) demo_params(); return "看代碼及注釋吧"; } // 無參數,無返回值函數演示 void function1() { // 空參數時,寫 void 和不寫 void 的區別(C 語言建議沒有參數時使用 void) /* void fun(); // 代表可以傳遞任意參數(C++ 則代表不能傳遞任何參數) fun(1); // 正常編譯(在本例中這麼做其實是會編譯錯誤的,因為用的是 C++ 編譯器) fun(1, 2, 3); // 正常編譯(在本例中這麼做其實是會編譯錯誤的,因為用的是 C++ 編譯器) */ /* void fun(void); // 代表不能傳遞任何參數 fun(1); // 編譯錯誤 fun(1, 2, 3); // 編譯錯誤 */ } // 有參數,有返回值函數演示 int function2(int a, int b) { // 這裡的 a 和 b 是形參,形參就是實參的副本 // 形參變量只在被調用期間才分配內存單元,調用結束立即釋放,也就是說形參變量只有在函數內才是有效的,離開該函數就不能再使用了,即形參的作用於在函數內 return a + b; } // 演示函數的遞歸調用 // return: 0 + 1 + 2 + 3 + ... + n long recursion(int n) { long result = 0 ; if (n > 0) { result += n; result += recursion(n - 1); } return result; } // 參數為數組類型的演示(之所以需要傳遞 aryLength 數組長度,是因為傳遞過來的 ary 是個指針,無法計算其指向的數組長度。就好像 main 函數似的,需要傳遞參數個數) void update(int ary[], int aryLength) { // 此處實參和形參其實指向的是一個地方 for (int i = 0; i < aryLength; i++) { ary[i] = 0; } } // 局部變量和全局變量的演示 void demo_variable1() { // 我是局部變量,作用域在函數內 int i = 1; { // 我是復合語句內的局部變量,作用域在復合語句內,不能與復合語句外的局部變量重名 int j = 1; } // 我是局部變量,如果全局變量有與我同名的,則“屏蔽”全局變量 int global01 = 200; // 上面“屏蔽”了全局變量,那我要怎麼引用全局變量呢?像下面這樣用“::” int global01Outside = ::global01; } // 變量存儲方式的演示 void demo_variable2() { // 從變量的生存期角度來分,可以分為靜態存儲方式和動態存儲方式 // 1、靜態存儲方式:是指在程序運行期間分配固定的存儲空間的方式 // 2、動態存儲方式:是在程序運行期間根據需要進行動態的分配存儲空間的方式 // 全局變量在程序運行期間都會被分配固定的存儲空間(靜態存儲方式) // 局部變量默認就是 auto 的,即動態分配存儲空間。下面這句寫全了就是 auto int i = 0;(動態存儲方式) int i = 0; // 如果希望函數中的局部變量的值在函數調用結束後不消失的話,則應該用 static 指定局部變量為“靜態局部變量”(靜態存儲方式) static int j = 0; // 用 register 指定“寄存器變量”,其會保存在 cpu 中的寄存器中。一個最佳場景是,將其作為循環控制的變量 // 寄存器變量無地址,所以不能用“&”對其取地址(C++ 可以取其地址,但是編譯器會自動將其變為內存變量)。另外,寄存器不夠用的話會自動變為內存變量 register int x = 0; // 用 volatile 保證變量必在內存中,而不會被放入 cpu 寄存器(如果編譯器認為某變量無外部修改,則為了優化會將其放入寄存器) volatile int y = 0; // 全局變量是在函數的外部定義的,它的作用域為從變量定義處開始,到本程序文件的末尾 // 如果在定義點之前的函數想引用該全局變量,則應該使用 extern 表明該變量在別的地方已經定義過了,在這裡要使用那個變量 extern int global02, global03; // 如果沒有這句的話,則編譯會報“未聲明的標識符”的錯誤 int p02 = global02; int p03 = global03; } int global02 = 200, global03 = 300; // 以下演示如何定義及使用參數不定的函數(可變參數) #include <stdarg.h> // 其定義了 va_start, va_arg, va_end (va 應該是 variable argument(可變參數)的簡寫) void demo_params() { // 計算 n 個整數的平均值,第一個參數代表後面的參數的個數 float average(int paramCount, ...); float result = average(4, 1, 2, 3, 4); // 2.5 } float average(int paramCount, ...) { // 定義一個參數列表 va_list va_params; long sum = 0; // 告知不定參數的個數,並准備讀取參數 va_start(va_params, paramCount); for (int i = 0; i < paramCount; i++) { // 一個一個地按照指定的類型讀取參數的值,每讀取完一個,參數指針就會向後移動繼續讀取下一個 int value = va_arg(va_params, int); sum += value; } // 停止讀取參數 va_end(va_params); return sum * 1.0f / paramCount; }
OK
[源碼下載]