點選上方藍字關注我們
在本文中,我們将通過一些附加資訊和一些有用的實作技術來結束對C函數的探索。
基本的C函數(例如,一個或兩個參數和一個傳回值)并不複雜。但是,C函數非常靈活,通過超越基礎知識,您可以更輕松地編寫代碼,并将一些有益的特性引入固件。
1.将函數原型放入頭檔案中有時我想知道一個人是否必須是計算機科學專業才能完全了解C語言功能原型。這确實是一個相當複雜的問題。我認為固件工程師可以放心地忽略這些細節,而隻需采取以下标準操作:始終為您的功能提供一個原型,并将這些原型放置在頭檔案中。函數原型是一行代碼,為編譯器提供函數自變量和傳回值的資料類型。例如:
- float ArithmeticMean(char Value1,char Value2,char Value3);
複制代碼
實際上,不必包含輸入參數的名稱,因為此時編譯器希望知道的隻是資料類型。是以,您也可以按如下方式編寫原型:
- float ArithmeticMean(char,char,char);
複制代碼
我更喜歡包含參數名稱,這可能是因為它允許我通過從函數定義中複制和粘貼來建立函數原型。 當函數原型被遺漏或放錯位置時,可能會發生奇怪的事情,而根據我的經驗,消除這些問題的最簡單方法是将所有函數原型放置在項目的所有源檔案中包含的頭檔案中。這樣可以確定您可以安全地在任何源檔案中使用任何函數,因為在調用每個函數之前,總是會對其進行聲明(即,在頭檔案中)。 例如,以下代碼段摘自一個名為“ Project_DefsVarsFuncs.h”的檔案。
- //function prototypes
- void Delay_us(unsigned int DelayCount);
- void Delay_10ms(unsigned int DelayCount);
- void Delay_seconds(unsigned int DelayCount);
- void Update_LCD(unsigned char SensorNumber, unsigned long displayValue);
- void LCD_Clear_All();
複制代碼
此頭檔案包含在我的源檔案中,如下所示:
- //-----------------------------------------------------------------------------
- // Includes
- //-----------------------------------------------------------------------------
- #include "Project_DefsVarsFuncs.h"
複制代碼
2.将函數聲明為靜态以避免命名沖突 随着固件項目變得越來越大和越來越複雜,您可能會發現要在不同的源檔案中重用相同的功能名稱。您可以使用“ static”關鍵字來完成此操作。如上所述,在這種情況下,您不會将函數原型放置在頭檔案中。 “ static”關鍵字将功能範圍限制為一個源檔案。這使您可以對不同源檔案中的不同功能使用相同的功能名稱。在下面顯示的示例中,該項目需要三個不同的ProcessData()函數-一個用于分析ADC資料,一個用于響應UART指令 ,另一個用于處理I 2 C消息。
我将“ static”關鍵字放在函數原型的前面,然後函數原型移到源檔案的頂部(即,在由函數體内的處理器指令 組成的“正常”代碼之前)。 當多個工程師将要從事同一固件項目時,“ static”關鍵字也很友善。如果兩個工程師正在不同的源檔案中工作,則使用靜态功能可以使工程師A選擇功能名稱,而不必擔心工程師B将為不同功能選擇相同名稱的可能性。 3.使用指針将數組傳遞給函數
嵌入式 應用程式經常使用數組-傳感器 讀數,ADC值,短ASCII消息等序列。在這種開發環境中,函數似乎有點尴尬,因為您無法将數組傳遞給C函數。确實,您不能像傳遞單個變量那樣傳遞數組,但是可以使用指針為函數提供對數組資料的通路權限。 如果将指針作為參數之一,然後在調用函數時傳遞數組辨別符,則函數主體中的語句可以使用該指針讀取和修改數組的内容。如果您對此概念感到有些困惑,建議您先閱讀有關C語言中數組的文章 ,然後閱讀有關指針的第一篇文章。 4.您可以使用指針調用函數 指針是儲存記憶體位址的變量。該位址通常辨別變量或數組第零個元素的位置。但是,指針也可以指向函數。
如果您已經閱讀了有關C函數的第一篇文章,您就會知道函數存儲 在代碼存儲器 的特定位置,就像變量存儲在資料存儲器的特定位置一樣。如果存儲在指針中的值是函數的起始位址,則可以使用指針來調用該函數。如果更改指針的值使其等于不同函數的起始位址,則可以使用同一指針來調用該不同函數。 以下代碼段顯示了如何聲明可與具有三個char參數和傳回類型float的函數一起使用的函數指針。
- float(* Ptr_to_Function)(char,char,char);
複制代碼
數組辨別符本質上是指向數組第零個元素的指針。同樣,功能名稱被解釋為功能的起始位址(在代碼存儲器中)。是以,可以将函數配置設定給函數指針,如下所示:
- Ptr_to_Function = ArithmeticMean;
複制代碼
現在,您可以使用Ptr_to_Function調用函數ArithmeticMean()。以下兩個語句是等效的:
- Average = ArithmeticMean(Temperature1, Temperature2, Temperature3);
- Average = (*Ptr_to_Function)(Temperature1, Temperature2, Temperature3);
複制代碼
5.盡可能使用局部變量 我認為,在許多情況下,我們的本能是在源檔案的頂部定義所有變量,然後将其保留在該位置。但是,養成在函數中使用局部變量的習慣是很好的。局部變量的範圍僅限于定義它的功能。換句話說,變量是在調用函數時建立的,并在函數完成其任務後消失。 我推薦局部變量有兩個原因。首先,它們允許您在不同的函數中重用相同的變量名。複雜的項目可能包含許多需要基本變量的功能,例如循環計數器 。我喜歡對循環計數 器重複使用“ n”,而不是逐漸周遊字母表中的所有字母。 其次,使用局部變量可能會導緻更快的代碼。我不是編譯器專家,但是我認為局部變量很可能放在寄存器中而不是存儲位置,并且通路寄存器要比通路記憶體快。
寄存器是處理器的組成部分,可以快速讀取和寫入資料。 結論
我們在這裡讨論了很多與C語言中函數使用有關的細節,并且我希望這些資訊可以幫助您提高固件的效率和功能(無雙關)。如果您有任何與功能相關的技巧,請随時在下面的評論部分中分享。