표준 라이브러리 헤더 <stdbit.h>

표준 라이브러리 헤더 <stdbit.h> (C23)

어떤 수가 2의 거듭제곱인지, 앞에서부터 0이 몇 개인지, 비트를 회전시키려면? 이런 비트 단위 처리는 매번 직접 루프를 돌리기엔 번거롭고 실수하기 쉬워요. <stdbit.h>는 수치 라이브러리의 일부로, C 객체의 바이트 순서·바이트·비트 표현을 다루는 타입 제네릭 함수 매크로와 매크로 상수를 제공해요. C23에서 처음 도입됐죠.

출처: cppreference

본문

함수(Functions)

아래 함수들은 모두 타입 제네릭 함수 매크로(type-generic function macro)예요. 부호 없는 정수 타입에 대해, 접미사로 타입이 구체화된 버전(_uc, _us, _ui, _ul, _ull)이 따로 있고, 인자 타입에 맞춰 자동 선택되는 제네릭 버전이 하나 더 있어요.

함수 설명
stdc_leading_zeros 최상위 비트(MSB)부터 시작해 연속된 0 비트의 개수
stdc_leading_ones 최상위 비트부터 시작해 연속된 1 비트의 개수
stdc_trailing_zeros 최하위 비트(LSB)부터 시작해 연속된 0 비트의 개수
stdc_trailing_ones 최하위 비트부터 시작해 연속된 1 비트의 개수
stdc_first_leading_zero 최상위 비트부터 시작해 처음 나오는 0 비트의 위치
stdc_first_leading_one 최상위 비트부터 시작해 처음 나오는 1 비트의 위치
stdc_first_trailing_zero 최하위 비트부터 시작해 처음 나오는 0 비트의 위치
stdc_first_trailing_one 최하위 비트부터 시작해 처음 나오는 1 비트의 위치
stdc_count_zeros 부호 없는 정수에서 0 비트의 개수
stdc_count_ones 부호 없는 정수에서 1 비트의 개수
stdc_has_single_bit 2의 거듭제곱인지 검사
stdc_bit_width 주어진 값을 표현하는 데 필요한 최소 비트 수
stdc_bit_floor 주어진 값보다 크지 않은 가장 큰 2의 거듭제곱
stdc_bit_ceil 주어진 값보다 작지 않은 가장 작은 2의 거듭제곱

매크로 상수(Macro constants)

매크로 설명
__STDC_ENDIAN_LITTLE__, __STDC_ENDIAN_BIG__, __STDC_ENDIAN_NATIVE__ (C23) 스칼라 타입의 엔디언(endianness)을 나타냄

__STDC_ENDIAN_NATIVE__는 실행 환경의 실제 엔디언에 따라 __STDC_ENDIAN_LITTLE__ 또는 __STDC_ENDIAN_BIG__ 중 하나와 같은 값이 돼요.

시그니처(Synopsis)

#define __STDC_VERSION_STDBIT_H__ 202311L

#define __STDC_ENDIAN_LITTLE__ /* implementation-defined */
#define __STDC_ENDIAN_BIG__ /* implementation-defined */
#define __STDC_ENDIAN_NATIVE__ /* implementation-defined */

unsigned int stdc_leading_zeros_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_leading_zeros_us(unsigned short value) [[unsequenced]];
unsigned int stdc_leading_zeros_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_leading_zeros_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_leading_zeros_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_leading_zeros(/*generic_value_type*/ value) [[unsequenced]];
unsigned int stdc_leading_ones_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_leading_ones_us(unsigned short value) [[unsequenced]];
unsigned int stdc_leading_ones_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_leading_ones_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_leading_ones_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_leading_ones(/*generic_value_type*/ value) [[unsequenced]];
unsigned int stdc_trailing_zeros_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_trailing_zeros_us(unsigned short value) [[unsequenced]];
unsigned int stdc_trailing_zeros_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_trailing_zeros_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_trailing_zeros_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_trailing_zeros(/*generic_value_type*/ value) [[unsequenced]];
unsigned int stdc_trailing_ones_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_trailing_ones_us(unsigned short value) [[unsequenced]];
unsigned int stdc_trailing_ones_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_trailing_ones_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_trailing_ones_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_trailing_ones(/*generic_value_type*/ value) [[unsequenced]];
unsigned int stdc_first_leading_zero_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_first_leading_zero_us(unsigned short value) [[unsequenced]];
unsigned int stdc_first_leading_zero_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_first_leading_zero_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_first_leading_zero_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_first_leading_zero(/*generic_value_type*/ value) [[unsequenced]];
unsigned int stdc_first_leading_one_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_first_leading_one_us(unsigned short value) [[unsequenced]];
unsigned int stdc_first_leading_one_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_first_leading_one_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_first_leading_one_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_first_leading_one(/*generic_value_type*/ value) [[unsequenced]];
unsigned int stdc_first_trailing_zero_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_first_trailing_zero_us(unsigned short value) [[unsequenced]];
unsigned int stdc_first_trailing_zero_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_first_trailing_zero_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_first_trailing_zero_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_first_trailing_zero(/*generic_value_type*/ value) [[unsequenced]];
unsigned int stdc_first_trailing_one_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_first_trailing_one_us(unsigned short value) [[unsequenced]];
unsigned int stdc_first_trailing_one_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_first_trailing_one_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_first_trailing_one_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_first_trailing_one(/*generic_value_type*/ value) [[unsequenced]];
unsigned int stdc_count_zeros_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_count_zeros_us(unsigned short value) [[unsequenced]];
unsigned int stdc_count_zeros_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_count_zeros_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_count_zeros_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_count_zeros(/*generic_value_type*/ value) [[unsequenced]];
unsigned int stdc_count_ones_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_count_ones_us(unsigned short value) [[unsequenced]];
unsigned int stdc_count_ones_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_count_ones_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_count_ones_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_count_ones(/*generic_value_type*/ value) [[unsequenced]];
bool stdc_has_single_bit_uc(unsigned char value) [[unsequenced]];
bool stdc_has_single_bit_us(unsigned short value) [[unsequenced]];
bool stdc_has_single_bit_ui(unsigned int value) [[unsequenced]];
bool stdc_has_single_bit_ul(unsigned long int value) [[unsequenced]];
bool stdc_has_single_bit_ull(unsigned long long int value) [[unsequenced]];
bool stdc_has_single_bit(/*generic_value_type*/ value) [[unsequenced]];
unsigned int stdc_bit_width_uc(unsigned char value) [[unsequenced]];
unsigned int stdc_bit_width_us(unsigned short value) [[unsequenced]];
unsigned int stdc_bit_width_ui(unsigned int value) [[unsequenced]];
unsigned int stdc_bit_width_ul(unsigned long int value) [[unsequenced]];
unsigned int stdc_bit_width_ull(unsigned long long int value) [[unsequenced]];
/*generic_return_type*/
stdc_bit_width(/*generic_value_type*/ value) [[unsequenced]];
unsigned char stdc_bit_floor_uc(unsigned char value) [[unsequenced]];
unsigned short stdc_bit_floor_us(unsigned short value) [[unsequenced]];
unsigned int stdc_bit_floor_ui(unsigned int value) [[unsequenced]];
unsigned long int stdc_bit_floor_ul(unsigned long int value) [[unsequenced]];
unsigned long long int stdc_bit_floor_ull(unsigned long long int value) [[unsequenced]];
/*generic_value_type*/
stdc_bit_floor(/*generic_value_type*/ value) [[unsequenced]];
unsigned char stdc_bit_ceil_uc(unsigned char value) [[unsequenced]];
unsigned short stdc_bit_ceil_us(unsigned short value) [[unsequenced]];
unsigned int stdc_bit_ceil_ui(unsigned int value) [[unsequenced]];
unsigned long int stdc_bit_ceil_ul(unsigned long int value) [[unsequenced]];
unsigned long long int stdc_bit_ceil_ull(unsigned long long int value) [[unsequenced]];
/*generic_value_type*/
stdc_bit_ceil(/*generic_value_type*/ value) [[unsequenced]];
unsigned char stdc_rotate_left_uc(unsigned char value, unsigned int count);
unsigned short stdc_rotate_left_us(unsigned short value, unsigned int count);
unsigned int stdc_rotate_left_ui(unsigned int value, unsigned int count);
unsigned long stdc_rotate_left_ul(unsigned long value, unsigned int count);
unsigned long long stdc_rotate_left_ull(unsigned long long value, unsigned int count);
/*generic_value_type*/
stdc_rotate_left(/*generic_value_type*/ value, generic_count_type count);
unsigned char stdc_rotate_right_uc(unsigned char value, unsigned int count);
unsigned short stdc_rotate_right_us(unsigned short value, unsigned int count);
unsigned int stdc_rotate_right_ui(unsigned int value, unsigned int count);
unsigned long stdc_rotate_right_ul(unsigned long value, unsigned int count);
unsigned long long stdc_rotate_right_ull(unsigned long long value, unsigned int count);
/*generic_value_type*/
stdc_rotate_right(/*generic_value_type*/ value, generic_count_type count);

시그니처와 정확히 일치하지 않는 점이 하나 있어요. cppreference 본문의 함수 목록에는 stdc_rotate_left/stdc_rotate_right(비트 회전)가 표에 빠져 있지만 시그니처에는 포함되어 있어서, 여기 시그니처에는 함께 담아 두었어요. 이 두 함수는 값을 비트 단위로 왼쪽/오른쪽 회전시키는 함수예요. 대부분의 함수가 붙이는 [[unsequenced]] 속성은 "부수 효과 없이 순수하게 계산만 한다"는 뜻이에요.

만약 구현이 <stdbit.h>를 제공하지 않는다면 __STDC_NO_STDBIT_H__가 정의되기도 해요. 타입 제네릭 버전은 인자 타입에 맞는 구체 버전을 자동으로 선택해 주므로, 실무에서는 제네릭 버전만 써도 충분한 경우가 많아요.

더 알아보기

  • 부호 없는 정수 타입의 비트 폭(INT_WIDTH 등)은 <limits.h>에서 확인해요.
  • 비트 표현 전반은 언어의 비트 필드(bit-field) 문서와 함께 보면 좋아요.