기본 콘텐츠로 건너뛰기

다중 선택값과 비트 연산

다중 Checkbox 선택 값을 선택된 합산 값으로 DB 에서 저장하고,
이를 읽어서 선택된 Checkbox 를 설정해야 한다는 문의가 들어 왔다.

문의에 답변을 해준 김에 정리를 해 놓도록 한다.

Unix를 써본 사람이라면 다중 플래그에 대한 것을 잘 알고 있을 것이다.
Unix에서 권한코드 (Read, Write, Execute, ...) 가 같은 맥락이기 때문이다.

비트 연산

비트 연산에서 Shift 연산자를 제외하면 & (and), | (or), ^ (xor), ~ (비트 반전)의
4개 연산자가 존재한다.

  • & 연산은 양쪽 모두 1인 경우만 1을 반환한다.
  • | 연산은 양쪽 모두 0인 경우만 0을 반환한다.
  • ^ 연산은 | 과 반대로 모두 1인 경우만 0을 반환한다.
  • ~ 연산은 모든 비트의 값을 반전시킨다. 즉 1의 보수(반대값)를 나타낸다.

물론 대상은 unsigned 정수를 기준으로 한다. 따라서 선언은 16비트 선언을 기준으로 한다.

샘플 코드

백문이 불여일타이니 코드부터 알아보도록 한다.

public static final int A = 0x01;    // 0000 0001
public static final int B = 0x02;    // 0000 0010
public static final int C = 0x04;    // 0000 0100
public static final int D = 0x08;    // 0000 1000
public static final int E = 0x10;    // 0001 0000
public static final int F = 0x20;    // 0010 0000
public static final int G = 0x40;    // 0100 0000
public static final int H = 0x80;    // 1000 0000

위의 선언과 이진 값에서 보이는 것과 같이 1, 2, 4, 8, ... 처럼
이진수로 증가하는 값이어야 하고 각 비트의 중복이 없어야 하는 것이 기본이다.

만일 사용자가 A 와 D를 선택했다고 하면 아래와 같이 처리가 된다.

0000 0001    // A
0000 1000    // D
---------
0000 1001    // A | D

즉 | 연산이 되어 0000 1001 인 값이 나오는 것이다.

만일 여기서 D를 끄고 싶은 경우는 어떻게 해야 할까?

답은 간단하다. 위에서 보수(반대값)에 대해서 알아 보았기 때문에
결과에 D 의 보수 값인 1111 0111 을 & 연산해 주면 된다.

0000 1001    // A | D
1111 0111    // ~ D
---------
0000 0001    // (A | D) & (~D)

따라서 하나의 변수에 여러 개의 플래그 값을 관리할 수 있게 된다.

int flag = 0x00;    // 변수 초기화
flag |= A;           // A 선택
flag |= D;           // D 선택
flag &= ~D;        // D 선택 해제

이런 원리를 이용해서 특정한 값에 대해서 플래그가 선택되었는지 여부를 확인할 수 있다.

if ((flag & A) == A);    // A 선택 상태
if ((flag & !(A | B)) != 0x00);    // A, B 이외에도 다른 플래그가 선택되어 있는 상태

위와 같이 하나의 값을 여러 개의 플래그로 사용하는 경우에 비트 연산이 사용되는 것이다.

댓글