我在編程領域還比較陌生,我正在閱讀的許多編碼最佳實踐都有效地說明了使用全局變量的充分理由很少(或者最好的代碼根本沒有全局變量)。 p p>
我已盡全力記住這一點,編寫軟件以使用SD卡建立Arduino接口,與計算機交談並運行電動機控制器時。
我目前擁有46個全局變量,用於大約1100行“入門級”代碼(沒有一行執行多個操作)。這是一個很好的比率,還是我應該進一步降低它?
我在這裡問這個問題是因為我特別關注在Arduino產品上編碼的最佳實踐,而不是一般的計算機編程。
>
我在編程領域還比較陌生,我正在閱讀的許多編碼最佳實踐都有效地說明了使用全局變量的充分理由很少(或者最好的代碼根本沒有全局變量)。 p p>
我已盡全力記住這一點,編寫軟件以使用SD卡建立Arduino接口,與計算機交談並運行電動機控制器時。
我目前擁有46個全局變量,用於大約1100行“入門級”代碼(沒有一行執行多個操作)。這是一個很好的比率,還是我應該進一步降低它?
我在這裡問這個問題是因為我特別關注在Arduino產品上編碼的最佳實踐,而不是一般的計算機編程。
>
它們本身並不是邪惡,但在沒有充分理由使用它們的情況下,它們的確會被過度使用。
在很多情況下,全局變量是有利的。特別是因為對Arduino進行編程與對PC進行編程有很大不同。
全局變量的最大好處是靜態分配。特別是對於大型和復雜的變量,例如類實例。由於缺乏資源,動態分配(使用 new
等)不受歡迎。
此外,您不會像普通C程序那樣得到單個調用樹(單個 main()
函數調用其他函數)-相反,您實際上獲得了兩個單獨的樹( setup()
調用函數,然後是 loop()
調用函數),這意味著有時全局變量是實現目標的唯一途徑(即,如果要在 setup()
和 loop()
中使用它) )。
所以不,它們不是邪惡的,在Arduino上,它們的使用比在PC上更多,更好。
很難在沒有看到實際代碼的情況下給出明確的答案。
全局變量並不是邪惡的,它們通常在嵌入式環境中有意義,在該環境中,您通常需要進行大量硬件訪問。您只有四個UART,只有一個I2C端口等。因此,對於與特定硬件資源相關聯的變量使用全局變量是有意義的。確實,Arduino核心庫做到了: Serial
, Serial1
等是全局變量。另外,代表程序全局狀態的變量通常是全局變量。
我目前有大約1100行[code]的46個全局變量。這是一個好比率嗎?[...]
與數字無關。對於每個全局變量,應該問自己一個正確的問題是,將它包含在globalscope中是否有意義。如果其中一些保持恆定值,則將它們限定為 const
:編譯器通常會優化其存儲。如果這些變量中的任何一個僅在單個函數內使用,請將其設為局部。如果您希望其值在函數調用之間保持不變,則將其限定為 static
。您還可以通過在一個類中將變量分組在一起並擁有該類的一個全局實例來減少“可見”全局變量的數量。但是只有在有意義的情況下才可以這樣做。為了僅擁有一個全局變量而創建一個大型 GlobalStuff
類將無法使代碼更清晰。
全局變量的主要問題是代碼維護。讀取一行代碼時,很容易找到作為參數傳遞或在本地聲明的變量的聲明。很難找到全局變量的聲明(通常需要使用IDE)。
當您有很多全局變量(已經有40個)時,很難找到一個明確的名稱不太長。使用名稱空間是闡明全局變量作用的一種方法。
在C中模仿名稱空間的一種較差的方法是:
靜態結構{int motor1,motor2;布爾傳感器;}手臂;
在英特爾或手臂處理器上,對全局變量的訪問比其他變量要慢。 arduino可能與此相反。
與所有事物一樣(除了真正的邪惡的goto之外),全局變量都有其位置。
例如如果您有一個調試串行端口或一個日誌文件,需要能夠從任何地方寫入該文件,那麼將其全局化通常是有意義的。同樣,如果您有一些關鍵的系統狀態信息,那麼將其全局化通常是最簡單的解決方案。不必將值傳遞給程序中的每個函數。
正如其他人所說,對於僅超過1000行的代碼而言,46似乎很多,但是卻不知道其中的細節。您正在做什麼,很難說是否過度使用它們。
但是,對於每個全球用戶,請問自己一些重要的問題:
名稱是否明確具體?我不會在其他地方不小心使用相同的名稱嗎?如果不更改名稱。
是否需要更改名稱?如果不是,則考慮使其成為const。
這是否需要在任何地方都可見,還是僅是全局的,以便在函數調用之間保持該值?因此,請考慮使其在函數中本地化並使用關鍵字static。
如果在我不小心的情況下通過代碼更改了代碼,事情真的會糟透了嗎?例如如果您有兩個相關的全局變量(例如名稱和ID號),它們是全局變量(請參見前面有關在幾乎各處都需要一些信息時使用全局變量的說明),則如果其中一個變量被更改而沒有其他麻煩的事情發生。是的,您可能只是小心一點,但有時稍微加強一點謹慎是件好事。例如,將它們放在另一個.c文件中,然後定義可以同時設置它們並允許您讀取它們的函數。然後,您僅將函數包括在關聯的頭文件中,這樣,您的其餘代碼只能通過已定義的函數訪問變量,因此不會弄亂事情。這基本上是做c ++類所允許的一種純粹的c方式,但不必學習如何定義和創建類,這樣您就不會立即學到太多。
-更新-我剛剛意識到您是在詢問Arduino特定的最佳實踐,而不是一般的編碼,而這更多是一個一般的編碼回复。但老實說並沒有太大的區別,好的做法就是好的做法。 Arduino的 startup()
和 loop()
結構意味著在某些情況下,您必須比其他平台多使用一點全局變量,但這並沒有太大改變,無論平台是什麼,您總是最終會在平台限制內力求做到最好。
儘管在為PC編程時不會使用它們,但對於Arduino,它們有一些好處。
在某些情況下,尤其是在性能方面,最好使用全局變量,而不是在需要時創建元素:
他們是邪惡的嗎?也許。全局變量的問題在於,它們可以在任何時間不受執行的任何功能或代碼段的訪問和修改。假設這可能導致難以追溯和解釋的情況。因此,希望將全局變量的數量最小化,如果可能的話,使數量回到零。
是否可以避免?幾乎總是可以。 Arduino的問題在於,它們迫使您採用這兩種功能方法,即假定您 setup()
和 loop()
。在這種情況下,您將無法訪問這兩個函數的調用方函數的範圍(可能是 main()
)。如果有的話,您將可以擺脫所有全局變量,而可以使用本地變量。
生動描述以下內容:
int main(){setup(); while(true){loop(); } return 0;}
這大概與Arduino程序的主要功能類似。然後,最好在 main()
函數的範圍內聲明 setup()
和 loop()
函數中所需的變量而不是全球範圍。然後,可以通過將它們作為參數傳遞給其他兩個函數(如果需要,可以使用指針)來訪問它們。
例如:
int main(){ int myVariable = 0;設置(&myVariable); while(true){loop(&myVariable); } return 0;}
請注意,在這種情況下,您還需要更改兩個函數的簽名。
因為這可能不可行也不合乎需要,我看到了實際上,這是從Arduino程序中刪除大多數全局變量而不修改強製程序結構的唯一方法。
如果我沒記錯的話,那麼您在為Arduino編程時完全可以使用C ++,而不是C。如果您還不熟悉 OOP(面向對象編程)或C ++ ,可能需要一些時間來適應和閱讀。
我的建議是創建一個Program類,並創建該類的單個全局實例。
請考慮以下示例程序:
class程序{public:Program();} void setup(); void loop(); private:int myFirstSampleVariable; int mySecondSampleVariable;}; Program :: Program():myFirstSampleVariable(0),mySecondSampleVariable(0){} void Program :: setup(){//您的安裝代碼在這裡} void Program :: loop(){//您的循環代碼在此處}編程程序; //您的單個globalvoid setup(){program.setup();} void loop(){program.loop();}
Voilà,我們擺脫了幾乎所有的globals 。開始添加應用程序邏輯的函數是 Program :: setup()
和 Program :: loop()
函數。這些函數可以訪問實例特定的成員變量 myFirstSampleVariable
和 mySecondSampleVariable
,而傳統的 setup()
和 loop()
函數無權訪問,因為這些變量已被標記為私有。這個概念稱為數據封裝或數據隱藏。
教您OOP和/或C ++有點超出了此問題的答案範圍,所以我在這裡停止。
總結:應該避免使用全局變量,並且幾乎總是可以大幅度減少全局變量的數量。同樣,當您為Arduino編程時。
最重要的是,我希望我的回答對您有所幫助:)
全局變量永遠不會邪惡。反對它們的一般規則只是讓您生存足夠長的時間來獲取經驗,以便做出更好的決定的拐杖。不管我們是在談論可能包含多個事物的全局數組或映射,還是仍然假設只有一個 這樣的列表或映射,而沒有多個獨立的數組或映射) 。
因此,在使用全局變量之前,您想問自己:我可以想使用不止一個這樣的東西嗎?如果事實確實如此,那麼您將必須修改代碼以取消全局化,然後您可能會發現代碼的其他部分依賴於唯一性假設,因此您也將不得不對其進行修復,並且該過程將變得乏味且容易出錯。之所以講授“不要使用全局變量”,是因為通常從一開始就避免全局變量的花費很小,並且避免了以後不得不支付大量費用的可能性。
但簡化的假設是全局變量還可以使您的代碼更小,更快,並且使用更少的內存,因為它不必傳遞使用的是什麼東西的概念,不必進行間接操作,也不必考慮所需的東西可能不存在,等等。在嵌入式系統上,與PC上相比,您更有可能受到代碼大小和/或CPU時間和/或內存的限制,因此這些節省很重要。而且許多嵌入式應用程序的要求也更加嚴格-您知道您的芯片僅具有某個外圍設備,用戶不能僅僅將另一個外圍設備插入USB端口或其他設備中。
需要多個看似獨特的東西的另一個常見原因是測試-僅將某個組件的測試實例傳遞給函數,而試圖修改組件的行為時,測試兩個組件之間的交互會更容易。全局組件是一個棘手的命題。但是嵌入式世界中的測試與其他地方的測試往往有很大的不同,因此這可能不適用於您。據我所知,Arduino沒有任何測試文化。
因此,在它們似乎值得使用時,請繼續使用它們。密碼警察不會來接你。只是知道錯誤的選擇可能會為您帶來更多的工作,因此,如果您不確定...
Arduino中的全局變量是邪惡的嗎?
包括全局變量在內,什麼都不是固有的邪惡。我將其描述為“必不可少的惡魔”-它可以使您的生活更加輕鬆,但應謹慎對待。
我還可以採取哪些措施來進一步減少全球人數?
使用包裝函數來訪問全局變量。因此至少要從範圍的角度進行管理。