2009-09-10 67 views
20

鑑於我有一個可能處於一個或多個真/假狀態的對象,我總是對模塊爲什麼經常使用標誌+位掩碼而不是使用多個布爾值有點模糊。爲什麼使用標誌+位掩碼而不是一系列布爾值?

它遍佈.NET框架。不知道這就是最好的例子,但在.NET框架有以下幾點:

public enum AnchorStyles 
{ 
    None = 0, 
    Top = 1, 
    Bottom = 2, 
    Left = 4, 
    Right = 8 
} 

所以給出一個錨的風格,我們可以使用位掩碼來找出哪些國家的選擇。但是,您似乎可以使用爲每個可能的值定義的bool屬性或單個枚舉值數組的AnchorStyle類/結構完成相同的操作。

當然,我的問題的主要原因是,我想知道如果我應該按照我自己的代碼類似的做法。

那麼,爲什麼要使用這種方法呢?

  • 內存消耗較少? (它不是似乎喜歡它會消耗比bools的數組/結構更少)
  • 比結構或數組更好的堆棧/堆性能?
  • 更快的比較操作?更快的增值/刪除?
  • 對於編寫它的開發者來說更​​方便嗎?
+2

不是說我發現了一個強有力的論點,但它確實消耗了更少的內存。它使用一個int(4字節),而每個布爾使用一個字節。所以,4個布爾使用相同的一個int。 32個布爾最多使用32個字節,而所有這些布爾可以使用相同的枚舉。如果你去不推薦的路徑,你可以使枚舉長8個字節(sizeof(long))。 – 2009-09-10 17:16:41

+0

感謝您澄清。它引導我到這篇文章:http://stackoverflow.com/questions/294905/why-in-net-system-boolean-takes-4-byte – 2009-09-10 21:38:54

+0

所以從響應很明顯,枚舉標誌比結構更輕量級/內存方面的布爾數組。但是,似乎也有一些.NET框架類可以很好地適用於該任務,例如BitVector32或BitArray。如何使用BitVector32(由uint支持)進行存儲並提供在特定索引處獲取/設置位(如bools)的屬性? Windows窗體似乎這樣做。爲開發人員提供更多代碼,但看起來它會表現良好,並且封裝將使下游API消費者更容易使用。嗯? – 2009-09-10 21:40:58

回答

13

這是傳統上減少內存使用的方法。所以,是的,它比較陳舊的C#:-)

作爲一種編程技術,它可能會在當前系統已經過時了,你會是相當好的使用布爾變量數組,但...

比較存儲爲位掩碼的值是快速的。使用AND和OR邏輯運算符並比較得到的2個整數。

它使用的內存要少得多。將所有4個示例值放入一個位掩碼將使用半個字節。使用一個布爾數組,最有可能會使用幾個字節的數組對象加上每個布爾長字。如果你必須存儲一百萬個值,你會明白爲什麼一個位掩碼版本更好。

這是比較容易管理,你只需要對付一個整數值,而布爾變量數組將存儲在完全不同,說的數據庫。

而且,由於存儲器的佈局,在比陣列每一個方面要快得多。它幾乎與使用單個32位整數一樣快。我們都知道,就數據操作而言,速度一樣快。

1

這是爲了速度和效率。基本上所有你正在使用的是一個int。

if ((flags & AnchorStyles.Top) == AnchorStyles.Top) 
{ 
    //Do stuff 
} 
+0

這是一個非常高層次的答案。你能具體說明哪些操作更快/更高效,爲什麼?或者鏈接到一篇證明你的說法合理的文章? – 2009-09-10 17:20:26

+0

我真的需要給你證明,使用本機類型和簡單的邏輯表達式是快速和高效的工作嗎? – ChaosPandion 2009-09-10 17:25:53

+0

不要忘記操作順序。你必須在這裏按位操作放置括號。 – 2009-09-10 17:54:24

12
  • 易以任意順序設置多個標誌。

  • 易於保存並獲得一系列0101011到數據庫。

+2

請注意,即使作爲單獨的列,SQL Server也會將它們優化爲單個字節:http://msdn.microsoft.com/en-us/library/ms177603.aspx – AaronLS 2013-01-16 23:44:51

6

除了其他功能之外,它更容易向位域添加新的位含義,而不是將新的布爾值添加到類中。它也比一系列布爾值更容易將位域從一個實例複製到另一個實例。

+0

在我看來,向類中添加布爾值是如: bool newState; 關於複製,複製一個結構似乎很容易。 – 2009-09-10 17:25:12

+0

@Winston:序列化格式發生變化,以及爲舊數據接受默認值的良好序列化程序,以及舊版本不丟棄未知字段的情況很難找到。二進制接口發生了變化,這可能會導致一連串所需的更新,並且需要對該結構進行全面的維護支持。 (當然,*合約*必須明確地陳述「未知位被忽略」或「未知位導致錯誤」)。而且,在實施層面上,整體處理更容易。 – peterchen 2009-09-10 17:36:51

+1

@Winston如果您創建了一個API,該怎麼辦?然後,所有可能升級到新版本的人都必須更改代碼,因爲新的bool已添加到方法中。而如果它是一個枚舉,那麼就不需要做任何改變來保持使用相同的代碼。這就是爲什麼。NET框架有利於布爾值的枚舉。 – 2009-09-10 17:46:00

3

事實上,它可以有更好的性能,主要是如果你的枚舉派生自一個字節。 在這種極端情況下,每個枚舉值將由一個字節表示,其中包含所有組合,最多爲256個。具有如此多的可能的組合布爾值將導致256個字節。

但即使如此,我並不認爲這是真正的原因。我更喜歡這些的原因是C#讓我處理這些枚舉的能力。我可以使用單個表達式添加多個值。我也可以刪除它們。我甚至可以使用枚舉將單個表達式同時比較多個值。通過布爾運算符,代碼可以變成更冗長的代碼。

+3

有256個組合,但只有8個標誌。不要混淆他們。 – Dykam 2009-09-10 17:33:48

+0

對不起,我的英文不夠清晰。你是對的。 – 2009-09-10 18:56:12

+1

256組合使用bool?它是8個bool值。 8個bool值不是256個字節。 – CoperNick 2014-02-11 12:40:14

5

它也可以使方法更清晰。想象一下有10個布爾與1個位掩碼的方法。

2

我絕不會用枚舉標誌,除非你正在處理一些非常嚴重的內存限制(不太可能)建議。你應該總是編寫優化維護的代碼。

有幾個布爾屬性使得它更容易閱讀和理解的代碼,更改值,並提供智能感知評論更不用說減少錯誤的可能性。如果有必要,你可以在內部總是使用枚舉標誌字段,只要確保你暴露了設置/獲取值的布爾屬性。

3

Raymond Chen有a blog post on this subject

當然,位字段保存數據存儲,但 你必須平衡它針對代碼大小,可調試和 減少多線程的 成本。

正如其他人所說,它的時間在很大程度上是過去。它仍然很有誘惑力,有點讓人覺得很有趣,很酷,但它不再更高效,它在維護方面有嚴重的缺陷,它不能很好地與數據庫一起玩,除非你在嵌入式世界,你有足夠的記憶。

+2

雷蒙德談論的是位域,而不是位掩碼。 – gbjbaanb 2009-09-11 13:30:22

1

從域模型的角度來看,它只是現實的模型在某些情況下更好。如果您有三個布爾類型,如AccountIsInDefault和IsPreferredCustomer和RequiresSalesTaxState,那麼將它們添加到單個Flags裝飾枚舉中並不合理,因爲它們不是同一個領域模型元素的三個不同值。

但是,如果您有一組類似的布爾值:

[Flags] enum AccountStatus {AccountIsInDefault=1, 
     AccountOverdue=2 and AccountFrozen=4} 

[Flags] enum CargoState {ExceedsWeightLimit=1, 
     ContainsDangerousCargo=2, IsFlammableCargo=4, 
     ContainsRadioactive=8} 

然後,它是能夠存儲帳戶的總狀態(或貨物)有用在一個變量中...表示一個域元素,其值可以表示任何可能的狀態組合。

1
  1. 空間效率 - 1位
  2. 時間效率 - 位比較是由硬件快速處理。
  3. 語言獨立性 - 數據可能由多個不同的程序處理,您無需擔心跨不同語言/平臺的布爾值實現。

大多數時候,這些都不值得在維修方面進行折中。然而,有些時候它是有用的:

  1. 網絡協議 - 將有降低的消息
  2. 舊版軟件的大小大的儲蓄 - 一旦我不得不添加一些信息追蹤到一些舊的軟件。

修改標題的成本:數百萬美元和多年的努力。 將信息硬編碼爲頭中未使用的2個字節的成本:0.

當然,在訪問和操作此信息的代碼中存在額外的成本,但這些都是由函數完成的所以一旦你定義了訪問器,它就不會比使用布爾值可維護。

+1

1.空間效率只適用於密集包裝或非常有限的環境; 2.時間效率取決於掩碼的有效使用(並且掩蓋和比較單個位肯定不比*比較單個布爾值更快); 3.不適用,錯誤地使用布爾類型錯誤地使用布爾類型。 – user2864740 2014-10-09 23:19:02

相關問題