2012-10-29 21 views
9

Nie mogę zrozumieć, co robi to makro. Są one zdefiniowane w linux-kernel, ale moje wątpliwości są niezależne od tego. Nie jestem w stanie zrozumieć, co robi linia (((x)+(mask))&~(mask)).wyrównaj makro kernel

#define ALIGN(x,a)    __ALIGN_MASK(x,(typeof(x))(a)-1) 
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) 

Każda pomoc doceniona.

Odpowiedz

19

Powiedzmy, że masz numer: 0x1006

Z pewnych powodów chcesz wyrównać go do granicy bajtów 4.

o promieniu 4-bajtowego, wiesz wyrównane wartości 0x1000, 0x1004, 0x1008 itp wtedy również znać wyrównane wartość 0x1006 jest 0x1008.

Jak uzyskać 0x1008? Maska na wyrównanie wartości wyrównania 4 jest (4 - 1) = 0x03

Teraz 0x1006 + 0x03 = 0x1009 i 0x1009 & ~0x03 = 0x1008

Ta operacja jest __ALIGN_MASK makro.

Jeśli chcesz przekazać wartość 4 (wyrównanie) zamiast bezpośrednio 0x03 (maska ​​wyrównanie), masz ALIGN makro

11
#define ALIGN(x,a)    __ALIGN_MASK(x,(typeof(x))(a)-1) 

wyrównanie, a, odlewa się do typu x „s, a następnie odejmuje się jeden. Wyrównanie powinno być potęgą 2, tak aby uzyskać pewną liczbę wzorca bitowego 00..011..11 typu x, czyli maski (k 1s, jeśli a = 2^k).

Następnie

#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) 

dodaje wartość maska ​​x tak, (x)+ (mask) jest co najmniej tak duża jak najmniejszą wielokrotnością dostosowania, który jest nie mniejszy niż x i mniejszy niż kolejnego wielokrotności. Następnie bitowe i uzupełniające maskę zmniejsza tę liczbę do tej wielokrotności wyrównania.

Dla masek postaci 2^k - 1, obliczanie

(x + mask) & ~mask 

jest taka sama jak

(x + 2^k - 1) - ((x + 2^k - 1) % (2^k)) 

lub

((x + 2^k - 1)/(2^k)) * (2^k) 
+0

Będzie to działać trick 'alignment' które nie są moc 2. –

+0

Nie, działa tylko dla potęgi 2. Jednak wyrównywanie jest użyteczne tylko dla potęg 2, więc żadne użyteczne przypadki nie są niewłaściwe. –