C의 비트 연산
Bitwise operations in CC 프로그래밍 언어에서는 비트 연산자를 사용하여 비트 레벨에서 연산을 수행할 수 있다.
비트 와이즈 연산은 비트 와이즈 연산자의 논리 상대인 AND, OR 연산자가 아닌 연산자를 특징짓는 바이트 레벨 연산에 의해 대조된다. 바이트 레벨 연산자는 개별 비트로 수행하지 않고 한 번에 8비트(바이트로 알려져 있음)의 문자열에서 수행된다. 그 이유는 바이트가 일반적으로 주소 지정 가능한 메모리의 가장 작은 단위(즉, 고유한 메모리 주소를 가진 데이터)이기 때문이다.
이는 비트 연산자에게도 적용되며, 이는 한 번에 1비트만 작동하더라도 바이트보다 작은 것은 입력으로 받아들일 수 없다는 것을 의미한다.
이들 연산자는 모두 C++, 그리고 많은 C-family 언어로도 이용 가능하다.
비트 연산자
C는 비트 조작을 위한 6개의 연산자를 제공한다.[1]
기호 | 연산자 |
---|---|
& | 비트 와이즈 AND |
| 비트 포함 OR |
^ | 비트 XOR(전용 OR) |
<< | 좌교대 |
>> | 우경화 |
~ | Bitwise NOT(하나의 보완) (단일) |
비트 와이즈 AND &
물다 | 비트 b | a & b (A AND b) |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
비트 와이즈 AND 연산자는 단일 앰퍼샌드: &
그것은 단지 피연산자의 진리 값보다는 피연산자의 비트에 작용하는 AND의 표현일 뿐이다. 비트 와이즈 이진 AND는 이진 형태로 숫자의 각 위치에 있는 비트의 논리적 결합(위 표에 표시)을 수행한다.
예를 들어, 바이트로 작업(문자 유형):
11001000 & 10111000 -------- = 10001000
첫 번째 숫자의 가장 중요한 비트는 1이고, 두 번째 숫자의 그것 또한 1이므로 결과의 가장 중요한 비트는 1이다. 두 번째 가장 중요한 비트에서는 두 번째 숫자의 비트는 0이기 때문에 우리는 0으로 결과를 얻었다.
비트 와이즈 OR
물다 | 비트 b | a b (a OR b) |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
비트 와이즈 AND와 마찬가지로 비트 와이즈 OR은 비트 레벨에서 논리적 분리를 수행한다. 두 비트가 모두 0일 때만 비트 중 하나가 1이고 0이면 결과는 1이다. 그것의 상징은
파이프로 불릴 수 있다.
11001000 10111000 -------- = 11111000
비트 와이즈 XOR ^
물다 | 비트 b | a ^ b (XOR b) |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
비트 와이즈 XOR(전용 또는)는 2비트를 추가하고 캐리어를 폐기하는 것과 동등한 배타적 분리를 수행한다. 결과는 0이 두 개 또는 두 개 있을 때만 0이 된다.[3] XOR를 사용하여 비트를 1과 0으로 전환할 수 있다. 그러므로, i = i ^ 1
루프에 사용되는 경우 값을 1과 0으로 전환하십시오.[4]
11001000 ^ 10111000 -------- = 01110000
시프트 연산자
두 개의 현명한 교대조 운영자가 있다. 그들은 그렇다.
- 우측 시프트(
>>
) - 좌측 시프트(좌측 시프트)
<<
)
우측 시프트 >>
우측 시프트 연산자의 기호는 >>
가동을 위해서는 2명의 피연산자가 필요하다. 그것은 왼쪽 피연산자의 각 비트를 오른쪽으로 이동시킨다. 연산자를 따르는 숫자는 비트가 이동되는 장소(즉, 오른쪽 연산자)의 수를 결정한다. 따라서 ch >> 3
모든 비트는 오른쪽으로 세 군데 정도 이동될 것이다.
단, 음수이거나 이 값의 총 비트 수보다 크거나 같은 시프트 피연산자 값은 정의되지 않은 동작을 유발한다는 점에 유의하십시오. 예를 들어 32비트의 부호 없는 정수를 이동할 때 32비트 이상의 이동량은 정의되지 않는다.
예:
- 변수인 경우
ch
비트 패턴 포함11100101
그때ch >> 1
결과가 나올 것이다.01110010
그리고ch >> 2
생산될 것이다00111001
.
여기서 비트가 오른쪽으로 이동하면 왼쪽에 동시에 빈 공간이 생성된다. 서명되지 않은 유형이나 서명된 유형의 음수가 아닌 값에 대해 수행할 경우 수행된 작업은 논리적인 이동으로 인해 빈 칸이 채워지게 된다. 0
s (0) 서명된 유형의 음수 값에 대해 수행하면 결과는 기술적으로 구현 정의되지만(컴파일러 종속)[5] 대부분의 컴파일러는 산술적 시프트를 수행하여 빈칸을 왼쪽 피연산자의 설정 사인 비트로 채운다.
우측 시프트를 사용하여 다음과 같이 비트 패턴을 2로 나눌 수 있다.
i = 14; // 비트 패턴 00001110 j = i >> 1; // 여기서 비트 패턴이 1로 변경되어 00000111 = 7이 14/2로 변경됨
우측 시프트 연산자 사용
C에서 우시프트 연산자의 일반적인 용도는 다음 코드에서 확인할 수 있다.
예:
#include <stdio.h> 공허하게 하다 쇼비트( 서명이 없는 인트로 x ) { 인트로 i=0; 을 위해 (i = (의 크기(인트로) * 8) - 1; i >= 0; i--) { 설탕을 넣다(x & (1u << i) ? '1' : '0'); } 활자화하다("\n"); } 인트로 본래의( 공허하게 하다 ) { 인트로 j = 5225; 활자화하다("%d(이진수) \t\t ", j); /* 주어진 경우 이진 문자열을 인쇄하는 함수가 있다고 가정함 소수 정수 */ 쇼비트(j); /* 우측 시프트 작동을 위한 루프 */ 을 위해 (인트로 m = 0; m <= 5; m++) { 인트로 n = j >> m; 활자화하다("%d 우측 변속 %d이(가) 제공하는 ", j, m); 쇼비트(n); } 돌아오다 0; }
위 프로그램의 출력은 다음과 같다.
5225 in binary 00000000000000000001010001101001 5225 right shift 0 gives 00000000000000000001010001101001 5225 right shift 1 gives 00000000000000000000101000110100 5225 right shift 2 gives 00000000000000000000010100011010 5225 right shift 3 gives 00000000000000000000001010001101 5225 right shift 4 gives 00000000000000000000000101000110 5225 우측 시프트 5로 0000000000000000000000000000000010100011 제공
좌교대 <<
좌측 시프트 연산자의 기호는 <<
. 왼쪽 피연산자의 각 비트를 오른쪽 피연산자가 표시한 위치 수로 왼쪽으로 이동시킨다. 그것은 오른쪽 교대 근무자의 그것과 반대방향으로 작동한다. 따라서 ch << 1
위의 예에서 우리는 다음과 같다. 11001010
. 생성된 빈 공간은 위와 같이 0으로 채워진다.
단, 음수이거나 이 값의 총 비트 수보다 크거나 같은 시프트 피연산자 값은 정의되지 않은 동작을 유발한다는 점에 유의하십시오. 이는 ISO 9899:2011 6.5.7 비트-와이즈 시프트 운영자의 표준에 정의되어 있다.예를 들어 32비트의 부호 없는 정수를 이동할 때 32비트 이상의 이동량은 정의되지 않는다.
왼쪽 시프트는 정수를 다음과 같이 2의 힘으로 곱하는 데 사용할 수 있다.
인트로 i = 7; // 10진수 7은 이진수(2^2) + (2^1) + (2^0) = 0000 0111 인트로 j = 3; // 소수점 3은 이진수(2^1) + (2^0) = 0000 0011 k = (i << j); // 좌측 시프트 연산은 값을 2 곱하여 소수점 j의 힘을 얻음 // i의 이진 표현에 0을 추가하는 것과 동등 // 56 = 7 * 2^3 // 0011 1000 = 0000 0111 << 0000 0011
예: 간단한 추가 프로그램
다음 프로그램은 AND, XOR 및 왼쪽 시프트(<)를 사용하여 두 개의 피연산자를 추가한다.
#include <stdio.h> 인트로 본래의( 공허하게 하다 ) { 서명이 없는 인트로 x = 3, y = 1, 합계를 내다, 나르다; 합계를 내다 = x ^ y; // XOR y 나르다 = x & y; // x AND y 하는 동안에 (나르다 != 0) { 나르다 = 나르다 << 1; // 캐리어를 좌측으로 이동 x = 합계를 내다; // x를 합으로 초기화 y = 나르다; // 운반선으로 y 초기화 합계를 내다 = x ^ y; // 합계를 계산한다. 나르다 = x & y; /* 운반이 계산되고 루프 조건이 평가된 후 프로세스가 다음 기간까지 반복됨 운반은 0과 같다. */ } 활자화하다("%u"\n", 합계를 내다); // 프로그램이 4를 인쇄함 돌아오다 0; }
비트 할당 연산자
C는 각 이진 산술과 비트 연산마다 복합 할당 연산자를 제공한다. 각 연산자는 왼쪽 피연산자와 오른쪽 피연산자를 받아들이고, 양쪽 모두에 대해 적절한 이항연산을 수행하고, 그 결과를 왼쪽 피연산자에 저장한다.[6]
비트 할당 연산자는 다음과 같다.
기호 | 연산자 |
---|---|
&= | 비트 AND 할당 |
= | 비트 포함 OR 할당 |
^= | 비트 배타적 OR 할당 |
<<= | 좌교대 배정 |
>>= | 오른쪽 교대 근무 할당 |
논리 등가물
비트 와이즈 연산자 중 4개는 등가 논리 연산자를 가지고 있다. 그들은 같은 진리표를 가지고 있다는 점에서 동등하다. 그러나 논리 연산자는 피연산자의 각 비트를 독립된 값으로 취급하기보다는 각 피연산자를 참 또는 거짓 중 하나의 값만 갖는 것으로 취급한다. 논리 연산자는 0이 거짓이고 0이 아닌 값이 참이라고 생각한다. 또 다른 차이점은 논리 연산자가 단락 평가를 한다는 것이다.
아래 표는 등가 연산자와 일치하며 a와 b를 연산자의 연산자로 나타낸다.
비트 와이즈 | 논리적인 |
---|---|
a & b | a && b |
a b | a b |
a ^ b | a != b |
~a | !a |
!=
와 같은 진리표를 가지고 있다. ^
하지만 진정한 논리 연산자와는 달리, 그 자체로 !=
논리 연산자를 엄격히 말하는 것은 아니다. 논리 연산자는 0이 아닌 값을 동일하게 취급해야 하기 때문이다. 논리 연산자로 사용됨 !=
먼저 피연산자를 정규화해야 한다. 두 피연산자에게 적용되지 않은 논리는 결과의 진실 테이블을 변경하지 않지만 비교 전에 모든 0이 아닌 값이 동일한 값으로 변환되도록 보장한다. 이 일은 !
0에서는 항상 1이 되고 !
0이 아닌 값은 항상 0이 된다.
예:
/* 등가 비트 및 논리적 연산자 검정 */ #include <stdio.h> 공허하게 하다 테스터 오퍼레이터(마를 뜨다* 이름을 붙이다, 서명이 없는 마를 뜨다 있었다, 서명이 없는 마를 뜨다 예상한); 인트로 본래의( 공허하게 하다 ) { // -- 비트 연산자 - // //비트로 포장된 진실 표 경시하다 서명이 없는 마를 뜨다 피연산자1 = 0x0A; //0000 1010 경시하다 서명이 없는 마를 뜨다 피연산자2 = 0x0C; //0000 1100 경시하다 서명이 없는 마를 뜨다 예상한그리고 = 0x08; //0000 1000 경시하다 서명이 없는 마를 뜨다 기대되거나 = 0x0E; //0000 1110 경시하다 서명이 없는 마를 뜨다 기대Xor = 0x06; //0000 0110 경시하다 서명이 없는 마를 뜨다 피연산자3 = 0x01; //0000 0001 경시하다 서명이 없는 마를 뜨다 예상 안 함 = 0xFE; //1111 1110 테스터 오퍼레이터("비트 AND", 피연산자1 & 피연산자2, 예상한그리고); 테스터 오퍼레이터("비트 OR", 피연산자1 피연산자2, 기대되거나); 테스터 오퍼레이터("비트 XOR", 피연산자1 ^ 피연산자2, 기대Xor); 테스터 오퍼레이터("비트와이즈 NOT", ~피연산자3, 예상 안 함); 활자화하다("\n"); // -- 논리 연산자 - // 경시하다 서명이 없는 마를 뜨다 F = 0x00; //제로 경시하다 서명이 없는 마를 뜨다 T = 0x01; //0이 아닌 값 // 배열로 포장된 진실 표 경시하다 서명이 없는 마를 뜨다 피연산자 배열1[4] = {T, F, T, F}; 경시하다 서명이 없는 마를 뜨다 피연산자 배열2[4] = {T, T, F, F}; 경시하다 서명이 없는 마를 뜨다 예상어레이앤드[4] = {T, F, F, F}; 경시하다 서명이 없는 마를 뜨다 예상 ArrayOr[4] = {T, T, T, F}; 경시하다 서명이 없는 마를 뜨다 예상 ArrayXor[4] = {F, T, T, F}; 경시하다 서명이 없는 마를 뜨다 피연산자 배열3[2] = {F, T}; 경시하다 서명이 없는 마를 뜨다 예상어레이Not[2] = {T, F}; 인트로 i; 을 위해 (i = 0; i < 4; i++) { 테스터 오퍼레이터("논리적 AND", 피연산자 배열1[i] && 피연산자 배열2[i], 예상어레이앤드[i]); } 활자화하다("\n"); 을 위해 (i = 0; i < 4; i++) { 테스터 오퍼레이터("논리적 OR", 피연산자 배열1[i] 피연산자 배열2[i], 예상 ArrayOr[i]); } 활자화하다("\n"); 을 위해 (i = 0; i < 4; i++) { //필수! 0이 아닌 값이 다른 경우 피연산자 테스터 오퍼레이터("논리적 XOR", !피연산자 배열1[i] != !피연산자 배열2[i], 예상 ArrayXor[i]); } 활자화하다("\n"); 을 위해 (i = 0; i < 2; i++) { 테스터 오퍼레이터("논리적 NOT", !피연산자 배열3[i], 예상어레이Not[i]); } 활자화하다("\n"); 돌아오다 0; } 공허하게 하다 테스터 오퍼레이터( 마를 뜨다* 이름을 붙이다, 서명이 없는 마를 뜨다 있었다, 서명이 없는 마를 뜨다 예상한 ) { 마를 뜨다* 결과 = (있었다 == 예상한) ? "통과" : "failed"; 활자화하다("%s %s, was: %X 예상: %X \n", 이름을 붙이다, 결과, 있었다, 예상한); }
위 프로그램의 출력은 다음과 같다.
Bitwise AND passed, was: 8 expected: 8 Bitwise OR passed, was: E expected: E Bitwise XOR passed, was: 6 expected: 6 Bitwise NOT passed, was: FE expected: FE Logical AND passed, was: 1 expected: 1 Logical AND passed, was: 0 expected: 0 Logical AND passed, was: 0 expected: 0 Logical AND passed, was: 0 expected: 0 Logical OR passed, was: 1 expected: 1 Logical OR passed, was: 1 expected: 1 Logical OR passed, was: 1 expected: 1 Logical OR passed, was: 0 expected: 0 Logical XOR passed, was: 0 expected: 0 Logical XOR passed, was: 1 expected: 1 Logical XOR passed, was: 1 expected: 1 Logical XOR passed, was: 0 expected: 0 Logical NOT passed, was: 1 expected: 1 Logical N통과된 OT: 0 예상: 0
참고 항목
참조
- ^ Kernighan; Dennis M. Ritchie (March 1988). The C Programming Language (2nd ed.). Englewood Cliffs, NJ: Prentice Hall. ISBN 0-13-110362-8. Archived from the original on 2019-07-06. Retrieved 2019-09-07. 많은 사람들에 의해 C에 대한 권위 있는 언급으로 간주된다.
- ^ a b "Tutorials - Bitwise Operators and Bit Manipulations in C and C++". cprogramming.com.
- ^ "Exclusive-OR Gate Tutorial". Basic Electronics Tutorials.
- ^ "C++ Notes: Bitwise Operators". fredosaurus.com.
- ^ "ISO/IEC 9899:2011 - Information technology -- Programming languages -- C". www.iso.org.
- ^ "Compound assignment operators". IBM. International Business Machines. Retrieved 29 January 2022.