2010-03-31 8 views
26

Per esempio, questo metodo da NSCalendar prende una maschera di bit:Come funzionano effettivamente queste maschere di bit?

- (NSDate *)dateByAddingComponents:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSUInteger)opts 

Quindi opzioni possono essere come:

NSUInteger options = kCFCalendarUnitYear; 

o simile:

NSUInteger options = kCFCalendarUnitYear | kCFCalendarUnitMonth | kCFCalendarUnitDay; 

Quello che non capisco è come si fa effettivamente? Voglio dire: come possono estrarre quei valori che sono uniti in options? Se volessi programmare qualcosa del genere, che potesse prendere una maschera di bit, come sarebbe?

+0

fare i tag come iPhone e Objective-C davvero aiutare quando questa informazione è vera (e anche la sintassi è la stessa) in molte lingue? – speedfranklin

risposta

32

Per fare questo, si vuole bit a bit e il valore che si sta testando contro la maschera, poi vedere se il risultato della AND è uguale alla maschera stessa:

if ((options & kCFCalendarUnitYear) == kCFCalendarUnitYear) { 
    // do whatever 
} 
+5

== kCFCalendarUnitYear sembra non necessario – sigjuice

+12

Infatti 'if (options & kCFCalendarUnitYear)' dovrebbe essere sufficiente perché qualsiasi valore diverso da zero significherà che il bit è stato impostato. – FRotthowe

+0

COOL uomo, questo è FREDDO! – dontWatchMyProfile

36

bitmasks sono piuttosto essenziali davvero. Si può pensare a come questo (C# fino a quando qualcuno in grado di convertire):

public enum CalendarUnits 
{ 
    kCFCalendarUnitDay = 1, // 001 in binary 
    kCFCalendarUnitMonth = 2, // 010 in binary 
    kCFCalendarUnitYear = 4, // 100 in binary 
} 

È quindi possibile utilizzare gli operatori bit per bit per combinare i valori:

// The following code will do the following 
// 001 or 100 = 101 
// So the value of options should be 5 
NSUInteger options = kCFCalendarUnitDay | kCFCalendarUnitYear; 

Questa tecnica è anche spesso utilizzato in routine di sicurezza :

public enum Priveledges 
{ 
    User = 1, 
    SuperUser = 2, 
    Admin = 4 
} 

// SuperUsers and Admins can Modify 
// So this is set to 6 (110 binary) 
public int modifySecurityLevel = SuperUser | Admin; 

Poi per controllare il livello di sicurezza, è possibile utilizzare il bit e per vedere se si dispone di autorizzazioni sufficienti:

012.351.
public int userLevel = 1; 
public int adminLevel = 4; 

// 001 and 110 = 000 so this user doesn't have security 
if(modifySecurityLevel & userLevel == userLevel) 

// but 100 and 110 = 100 so this user does 
if(modifySecurityLevel & adminLevel == adminLevel) 
    // Allow the action 
+2

Si noti che a causa della precedenza degli operatori, 'if (modifySecurityLevel & userLevel == userLevel)' deve essere "if ((modifySecurityLevel & userLevel) == userLevel)" altrimenti l'espressione verrà sempre valutata su true. – Drahcir

+0

È inoltre possibile eseguire lo spostamento dei bit in questo modo: = 1 << 1; – Mark

6

La chiave è ricordare che ognuno di quei valori che si fondono in "opzioni" è in realtà solo un numero. Non sono sicuro di quanto tu sia familiare con il binario, ma puoi pensare in termini decimali e aggiungere solo numeri anziché OR.

Diciamo che A = 10, B = 100, e C = 1000

Se si volesse impostare le opzioni = A + B, poi opzioni sarebbe uguale 110. Il metodo chiamato sarebbe poi guardare le "decine "luogo per A, il posto" centinaia "per B e il posto" migliaia "per C. In questo esempio, c'è un 1 è il posto di centinaia e il luogo delle decine, quindi il metodo saprebbe che A e B sono stati impostati nelle opzioni.

È un po 'diverso dal momento che i computer utilizzano il binario non decimale, ma penso che l'idea sia molto simile, ea volte è più facile pensarci in un sistema di numerazione familiare.

+2

buona spiegazione! Grazie! – dontWatchMyProfile

+2

L'idea non è solo simile, ma esattamente la stessa cosa. Solo la base è diversa: 2 vs 10. Chi ha familiarità con la riga di comando UNIX/Linux lo ha fatto anche in base-8 (ottale), in quanto è così che funzionano le maschere di autorizzazione numerica del comando chmod. –

16

bitmasks funziona perché in binario, ciascuna potenza di 2 (cioè, 2 = 1, 2 = 2, 2 = 4) occupa un singolo punto nella sequenza di bit. Per esempio:

decimal | binary 
1  | 0001 
2  | 0010 
4  | 0100 
8  | 1000 

Quando si or (l'operatore | in linguaggi C-like) due numeri a e b insieme in c, che stai dicendo "prendere i bit che si trovano in a, b, o entrambi e metterli in c."Dal momento che una potenza di due rappresenta una singola posizione in una stringa binaria, non c'è alcuna sovrapposizione, e si può determinare quelli che sono stati fissati. Per esempio, se si or 2 e 4

0010 | 0100 = 0110 

Notate come fondamentalmente combinato il . due D'altra parte, se si or 5 e 3:.

decimal | binary 
5  | 0101 
3  | 0011 

0101 | 0011 = 0111 

preavviso che non abbiamo modo di distinguere quale bit è venuto da dove, perché non c'era sovrapposizione tra la rappresentazione binaria di ogni

Questo beco è più evidente con un altro esempio. Prendiamo i numeri 1, 2, e 4 (tutte le potenze di due)

0001 | 0010 | 0100 = 0111 

Questo è lo stesso risultato di 5 | 3! Ma dal momento che i numeri originali sono potenze di due, possiamo dire in modo univoco da dove proviene ogni bit.

+0

Ottimo esempio ma non capisco come la tua ultima frase. Come possiamo sapere se lo 0111 è venuto da 0001 | 0010 | 0100 O 0101 | 0011? – joels

+0

Il punto è che sappiamo * a priori * che le bandiere sono solo due potenze. In altre parole, sappiamo che è "0001 | 0010 | 0100 |' e non '0101 | 0011' perché quest'ultimo non è semplicemente un'opzione, dal momento che non consiste solo di due potenze. – notJim

0

Ho trovato che Calculator.app è utile per visualizzare le maschere di bit. (Basta selezionare Visualizza> Programmatore, quindi fare clic sul pulsante per Mostra binario). (È possibile fare clic su uno qualsiasi degli 0 o 1 nella tabella binaria per attivare o disattivare tali bit oppure immettere numeri decimali o esadecimali (utilizzare 8 | 10 | 16 NSSegmentedControl per passare da una rappresentazione all'altra)).

3
typedef NS_OPTIONS(NSUInteger, MyOption) 
{ 
    OptionNone = 0, 
    OptionOne = 1 << 0, 
    OptionTwo = 1 << 1, 
    OptionThree = 1 << 2 
}; 

if (givenValue & OptionOne) { 
    // bit one is selected 
} 

if (givenValue & OptionTwo) { 
    // bit two is selected 
} 

http://en.wikipedia.org/wiki/Mask_(computing)

Problemi correlati