마스크를 만들고 필드를 배치하는 기본 도구인데, C 표준이 정하지 않은 구석이 많다.
데는 곳 셋
1 << 31 /* 1 은 int(부호 있음) → 부호 비트를 침범, 미정의 동작 */
1u << 31 /* 이렇게 쓴다 */
uint32_t v; v << 32; /* 타입 폭 이상 시프트 = 미정의. 0 이 되리라 기대하면 안 된다 */
int8_t x = -8; x >> 1; /* 음수의 오른쪽 시프트는 구현 정의(대개 산술 시프트) */
세 경우 모두 컴파일은 되고, 어떤 툴체인에서는 의도대로 돌아간다. 그래서 더 위험하다.
실무 규칙
상수에 u 를 붙인다 1u << n
이동량이 타입 폭보다 작은지 확인 n < 32
부호 있는 값은 시프트하지 않는다 나눗셈이 의도라면 / 를 쓴다
넓은 타입으로 먼저 승격한다 ((uint32_t)a << 16) | b
곱셈·나눗셈 대용은 이제 불필요하다
옛 코드에 x >> 1 로 2로 나누는 관용구가 많지만, 요즘 컴파일러는 / 2 를 알아서 시프트로 바꾼다.
의도를 그대로 쓰는 편이 읽기 쉽고 부호 함정도 피한다.