# 位操作在 Android 源码中的运用

— Antoine de Saint-Exupéry 法国作家兼飞机设计师

#### 位操作与集合

// x, y, z are uint8
x = 1 << 1 | 1 << 5 // x = 00100010, set {1, 5}
y = 1 << 1 | 1 << 2 // y = 00000110, set {1, 2}

z = x & y // z = 00000010, intersection {1}
z = x | y // z = 00100110, union {1, 2, 5}
z = x ^ y // z = 00100100, symmetric difference {2, 5}
z = x &^ y // z = 00100000, difference {5}

z = x << 1 // z = 01000100, set {2, 6}
z = x >> 1 // z = 00010001, set {0, 4}

x, y, z 均为8位的无符号整数，这里的位集的概念可能大伙已经看出来了，也就是二进制数从低位到高位不为0的位组成的集合。而&，|, ^, &^ 分别表示两个集合A，B的交集并集对称差集差集；而<<，>>可以理解为对集合中的元素加1或减1，当元素超出了集合的范围时则将该元素从集合中移除。

1100 0000 1010 1000 0000 0011 0000 0110 (192.168.3.6)
& 1111 1111 1111 1111 1111 1111 0000 0000 (255.255.255.0)
-----------------------------------------
1100 0000 1010 1000 0000 0011 0000 0000 (192.168.3.0)

Android 源码中大量使用了掩码。

#### View.MeasureSpec

private static final int MODE_SHIFT = 30;
private static final int MODE_MASK = 0x3 << MODE_SHIFT;

/**
* Measure specification mode: The parent has not imposed any constraint
* on the child. It can be whatever size it wants.
*/
public static final int UNSPECIFIED = 0 << MODE_SHIFT;

/**
* Measure specification mode: The parent has determined an exact size
* for the child. The child is going to be given those bounds regardless
* of how big it wants to be.
*/
public static final int EXACTLY = 1 << MODE_SHIFT;

/**
* Measure specification mode: The child can be as large as it wants up
* to the specified size.
*/
public static final int AT_MOST = 2 << MODE_SHIFT;

/** Creates a measure specification based on the supplied size and mode. */
public static int makeMeasureSpec(int size, int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
}
}

/** Extracts the mode from the supplied measure specification. */
public static int getMode(int measureSpec) {
}

/** Extracts the size from the supplied measure specification. */
public static int getSize(int measureSpec) {
}

<TextView
layout_width="255px"
layout_height="wrap_content" />

0000 0000 0000 0000 0000 0000 1111 1111 {0,1,2,3,4,5,6,7}
| 0100 0000 0000 0000 0000 0000 0000 0000 {30}
-----------------------------------------
0100 0000 0000 0000 0000 0000 1111 1111 {0,1,2,3,4,5,6,7,30}

#### View.getVisibility() | View.setVisibility(int)

/** The view flags hold various views states. */
int mViewFlags;

static final int VISIBILITY_MASK = 0x0000000C;
public int getVisibility() { return mViewFlags & VISIBILITY_MASK; }

static final int ENABLED_MASK = 0x00000020;
public boolean isEnabled() { return (mViewFlags & ENABLED_MASK) == ENABLED; }

static final int CLICKABLE = 0x00004000;
public boolean isClickable() { return (mViewFlags & CLICKABLE) == CLICKABLE; }

static final int WILL_NOT_DRAW = 0x00000080;
public boolean willNotCacheDrawing() { return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; }

// ...

void setFlags(int flags, int mask) {
// ...
int old = mViewFlags;

int changed = mViewFlags ^ old;
if (changed == 0) {
return;
}

final int newVisibility = flags & VISIBILITY_MASK;
if (newVisibility == VISIBLE) {
// ...
}

/* Check if the GONE bit has changed */
if ((changed & GONE) != 0) {
// ...
}

/* Check if the VISIBLE bit has changed */
if ((changed & INVISIBLE) != 0) {
// ...
}

if ((changed & VISIBILITY_MASK) != 0) {
// If the view is invisible, cleanup its display list to free up resources
// ...
}
// ...
}

#### 答案

#include <stdio.h>

#define BITSPERWORD 32
#define SHIFT 5
#define N 10000000
#define a[1 + N / BITSPERWORD]

void set(int i) { a[i >> SHIFT] |= (1 << (i & MASK)); }

void clr(int i) { a[i >> SHIFT] &= ~(1 << (i & MASK)); }

int test(int i) { return a[i >> SHIFT] & (1 << (i & MASK)); }

int main() {
int i;
for (i = 0; i < N; i++) {
clr(i);
}

while (scanf("%d", &i) != EOF) {
set(i);
}

for (i = 0; i < N; i++) {
if (test(i)) {
printf("%d\n", i);
}
}

return 0;
}

#### 参考

• 《编程珠玑》
• 《The Go Programming Language》
• 图片来自signalvnoise
One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.