비트 연산자와 열거형 비트 연산자는 이진 숫자의 문자열로 표현된 정수적 수식에 대한 연산을 수행한다. 이 연산자는 분명히 시스템 종속적이다. 따라서 여기서는 8비트 바이트, 4바이트 워드, 2의 보수표현의 정수, 그리고 ASCII 문자 코드를 갖는 기계에 한하여 논의하기로 한다.
비트 연산자
우선순위 와 결합법칙
비트별 보수 ~ 연산자는 보수 연산자(complement operator) 예를 들면 : int a = 70707; 이 연산자는 비트열의 0은 1로, 1은 0으로 바꾸는 연산자이다. 예를 들면 : int a = 70707; 2진수로 표현 00000000 00000001 00010100 00110011 ~a를 2진수로 표현하면 11111111 11111110 11101011 11001100
2의 보수 음이 아닌 정수 n의 2의 보수표현은 n을 2진수로 표현함으로써 얻을 수 있는 비트열이다.
비트별 이진 논리 연산자 & : and ^ : exclusive or | : inclusive or 다음 표는 비트별 연산결과를 보여준다.
비트별 연산자의 예
왼쪽 및 오른쪽 이동 연산자(1) expr1 << expr2 오른쪽 끝에서는 이동한 수 만큼이 0으로 채워진다. Declarations and initializations char c = ‘ Z ’ ; Expression Representation Action c 00000000 00000000 00000000 01011010 unshifted c << 1 00000000 00000000 00000000 10110100 left-shifted 1 c << 4 00000000 00000000 00000000 10100000 left-shifted 4 c << 31 00000000 00000000 00000000 00000000 left-shifted 31
왼쪽 및 오른쪽 이동 연산자(2) 오른쪽 이동 연산자 >> 는 왼쪽 이동 연산자의 경우와 다르다. unsigned의 경우에는, 0이 왼쪽 끝에 삽입된다. signed에서는 어떤 컴퓨터에서는 0이 삽입되고, 어떤 시스템에서는 부호비트가 삽입된다.
왼쪽 및 오른쪽 이동 연산자(3) 다음표는 이동 연산자에 관한 우선순위 및 결합법칙을 설명해 주고있다.
Mask(1) 마스크는 다른 변수나 식으로부터 원하는 비트를 추출하는 데 사용되는 상수나 변수이다. int 형 상수 1은 다음과 같이 쓸수 있다. 00000000 00000000 00000000 00000001 다음은 이 마스크를 사용하여 0과 1을 교대로 출력하는 프로그램이다. int i, mask = 1; for (i = 0; i < 10; ++i) printf("%d", i & mask);
Mask(2) 만약 어떤 식에서 특정 비트 값을 찾길 원한다면 그 비트 위치에는 1, 그외 다른 비트 위치에는 0을 갖는 마스크를 사용하면 된다. For example, (v & (1 << 2)) ? 1 : 0 v의 세번째 비트에 따라 1이나 0을 갖게 된다.
Mask(3) " 255 는 하위 바이트에 대한 마스크”라고 한다. 마스크의 다른 예로서, 다음과 같은 비트 형태를 갖는 상수 255, 다시 말해서 (28 - 1)를 살펴보자. 00000000 00000000 00000000 11111111 하위의 바이트가 모두 1이므로 (v & (1 << 2)) ? 1 : 0 결과는 상위의 모든 바이트 값은 0이 되고 하위 바이트 값은 v의 하위 바이트와 동일한 값을 갖는 비트 형태가 된다. " 255 는 하위 바이트에 대한 마스크”라고 한다.
SOFTWARE TOOLS:int형의 비트별 출력 /* Bit print an int expression. */ #include <limits.h> void bit_print(int a) { int i; int n=sizeof(int)*CHAR_BIT; /* in limits.h */ int mask = 1 << (n - 1); /* mask = 100...0 */ for(i = 1; i <= n; ++i) { putchar(((a & mask) == 0) ? '0': '1'); a <<= 1; if(i % CHAR_BIT == 0 && i < n) putchar(' '); }
Packing and Unpacking(1) /* Pack 4 characters into an int. */ #include <limits.h> int pack(char a, char b, char c, char d) { int p = a; /* p will be packed with a, b, c, d */ p = (p << CHAR_BIT) | b; p = (p << CHAR_BIT) | c; p = (p << CHAR_BIT) | d; return p; }
Packing and Unpacking(2) /* Unpack a byte from an int. */ #include <limits.h> char unpack(int p, int k) /* k = 0, 1, 2, or 3 */ { int n = k * CHAR_BIT; /* n = 0, 8, 16, or 24 */ unsigned mask = 255; /* low-order byte */ mask <<= n; return ((p & mask) >> n); }
열 거 형(1) 예약어 enum 은 열거형을 선언하는 데 사용된다. 이것은 유한집합을 명명하고, 그 집합의 원소로서 식별자를 선언하는 수단을 제공한다. 예를 들어 다음과 같은 선언을 고려해 보자. enum day {sun, mon, tue, wed, thu,fri,sat}; 이 선언은 사용자 정의형의 enum day 를 생성한다. 이들은 int 형의 상수이다. 기본적으로 첫 번째 원소는 0 값을 갖고, 각 열거된 순서에 따라 1,2, ... 등의 정수값을 가진다.
열 거 형 (2) 열거자는 초기화될 수 있으며, 또한 필요한 경우 이 틀과 함께 변수들을 선언할 수 있다. 다음 예를 보자. enum suit {clubs=1,diamonds,hearts,spades} a, b, c; club가 1로 초기화 되었으므로, diamonds, hearts, spades는 각각 2,3,4의 값을 가진다. enum fruit {apple=7,pear,orange=3,lemon} frt; apple이 7로 초기화되었기 때문에 pear는 8로 초기화된다. 마찬가지로 orange는 3으로 초기화되었으므로, lemon의 초기화 값은 4이다.
열 거 형(3) 다음과 같이 식별자에게 여러 개의 값이 허용될 수 있지만, 식별자 자체는 중복되면 안 되고 유일해야 한다. enum veg {beet=17,carrot=17,corn=17} vege1, vege2; enum {fir, pine} tree; 태그 이름은 반드시 나타낼 필요는 없다. 태그 이름이 없으므로, enum {fir, tree} 의 형으로 다른 변수를 선언 할 수는 없다.
열거형 선언의 구문 : enum_declaration ::= enum_type_specifier identifier { , identifier }0+ ; enum_type_specifier ::= enum e_tag { e_list } | enum e_tag | enum { e_list } e_tag ::= identifier e_list ::= enumerator { , enumerator }0+ enumerator ::= identifier { = constant_integral_expression } opt