' [C/C++] 5.1강 - C의 다양한 연산자(사칙대입연산자,증감연산자,sizeof,비트연산자)

Programming/C & C++

[C/C++] 5.1강 - C의 다양한 연산자(사칙대입연산자,증감연산자,sizeof,비트연산자)

mdisprgm 2021. 6. 12. 01:31
728x90

(이 포스팅은 지난 5강과 이어짐)

(5) 사칙 대입 연산자

사실 이것이 정확한 명칭인지는 모르겠지만

 

그런데 사칙 연산 결과를 바로 대입하는 연산자이기 때문에

 

그냥 마음대로 이름을 붙임 ㅋ

 

종류는 사칙 연산자의 개수와 같으며 형태도 굉장히 직관적이다.

 

1. +=

2. -=

3. *=

4. /=

5. %=

 

사용법은 아래를 보면 바로 이해가 갈 정도로 쉽다.

 

int a = 10;

a += 1;//이것과
a = a + 1;//이것은 같은 표현임

//마찬가지로
a = a * 3;//이것과
a *= 3;//이것은 같은 표현임

+ (더하기) 연산을 수행한 결과를 = (대입)

* (곱하기) 연산을 수행한 결과를 = (대입)

 

 

그럼 이제 아래 코드를 실행해보면

#include <stdio.h>

int main()
{
    int a = 10;
    a+=1;//1을 더함, 10 + 1 = 11
    a%=3;//3으로 나눈 나머지, 11 % 3 = 2
    a*=2;//2를 곱함, 2 * 2 = 4
    printf("a is %d\n", a);
}

이렇게 결과가 나온다.

 

(6) 증감 연산자

사칙 대입 연산자로 연산이 굉장히 편리해진 것을 느낄 수 있다.

 

그런데 여기서 코드를 더 줄이기 위해 만들어진 연산자들이 또 있는데,

 

바로 단순히 1을 더하거나, 1을 빼는 것만을 위한 연산자들이다.

 

이 역시 굉장히 기억하기 쉬운 형태로 돼있다.

 

1. ++

2. --

 

++은 해당 변수에 1을 더하는 연산자,

--은 해당 변수에 1을 빼는 연산자이다.

 

 

다만 이것은 호출되는 위치에 따라서 작동 방식이 달라지는데

 

이런 증감 연산자는 두 가지 방식으로 호출할 수 있다.

int x;

x = 5;

x++;//변수 뒤에 붙이기, 후위 연산자

--x;//변수 앞에 붙이기, 전위 연산자

 

두 가지 방식의 차이는?

 

간단하지만, 이러한 차이를 이용해 여러 기법들이 만들어지곤 한다.

 

 

전위 연산자는 호출되면 즉시 x에 + 1 을 하고, 증가된 값을 반환한다.

 

그러나 후위 연산자는 일단 x에는 아무 일도 일어나지 않고 코드를 실행하고

 

그 작업이 끝나면 그제서야 x에 + 1을 하게 된다. 즉, 반환되는 값은 1만큼 증가되기 전 값이다.

 

아래 예제를 보자.

#include <stdio.h>

int main() {
    int x;
    x = 5;
    
    printf("#1 : %d\n", x++);//일단 5가 출력된다
    //그러고 나서 5 + 1이 된다.
    
    printf("#2 : %d\n", x);//따라서 여기서 출력해야 6이 나온다.
    
    printf("#3 : %d\n", --x);//그러나 전위 연산자는
    //먼저 1을 뺀다
    //따라서 #3은 6 - 1 = 5가 다시 출력된다.
    
}

 

#1은 후위 연산자라 출력된 후 값이 변경됐지만

#3은 전위 연산자라 변경된 값이 출력된 걸 볼 수 있다.

 

 

다른 변수에 대입을 해본다면

이렇게 결과가 나온다.

 

 

처음에 x = 0인데, y에 대입하고 나서 x + 1을 했으므로

 

첫 줄에는 x : 1, y : 0 이 출력되는데

 

다시 y = ++x; 를 하면 먼저 x + 1이 되어 x = 2가 되고

 

그것이 y에 대입되어 x, y 둘다 2로 출력되는 것을 볼 수 있습니다.

 

 

(7) 비트 연산자

비트 연산자는

 

이름 그대로 비트를 다룰 수 있는 연산자이다.

 

C언어에서 가장 작은 size를 가진 자료형인 char, 이 크기가 1Byte여서 다른 언어에서는

 

char라는 이름 대신 byte라는 이름을 사용하기도 한다.

 

이 Byte가 모든 값의 기본이 되지만

 

이 역시 나눠보면 8Bits로 이루어져있기 때문에

 

그 Bit들을 잘 활용해서 효율적인 연산을 할 수 있다.

 

 

예를 들어 정수 50을 비트로 저장하면 다음과 같습니다.

 

00110010

 

이러한 비트를 가지고 여러 연산을 할 수 있는 건데

 

그 종류는 다음과 같다.

 

1. & (AND)

2. | (OR)

3. ^ (XOR)

4. >>, << (Shift)

5. ~ (NOT)

 

각각 AND 연산자, OR 연산자, XOR 연산자, Shift 연산자, NOT 연산자라고 불린다

 

 

ㄱ) AND 연산자부터 살펴보면

 

AND 연산자는 비트를 하나씩 비교해서 둘 다 1이면 1, 하나만 1이거나 둘 다 1이 아니면 0으로 반환한다.

 

예시를 들어서

 

정수 3은 바이너리 형태로 0011이고

 

정수 5는 바이너리 형태로 0101이다.

 

그림을 그려보면

 

 

(3 & 5)

↓↓↓

 

0011

0101

-------

0001

이 된다.

 

3, 5 모두 마지막 비트만 양쪽 값이 1이기 때문에

 

결과가 0001이 나왔다.

 

즉 3 & 5는 1과 같습니다.

printf("%d\n", 3 & 5);//1

 

ㄴ) OR 연산자는

 

AND와 다르게 둘 중 하나만 1이어도 결과가 1이 된다.

 

즉 3 | 5 는 이렇게 된다.

 

(3 | 5)

↓↓↓

 

0011

0101

-------

0111

 

둘 중 하나만 1일 때 1이 되는 것이 아니라, 둘 중 하나라도 1이면 1이 되기 때문에

 

세 비트가 1이 되었다. 

 

따라서 printf로 출력하면 7이 출력된다.

printf("%d\n", 3 | 5); //7

 

ㄷ) XOR 연산자가 좀 흥미로운데

 

OR과 비슷하지만, 차이점은 반드시 두 비트가 달라야 한다는 것이다.

 

즉, 둘 중 하나만 1일 때 1이 된다.

 

(3 ^ 5)

↓↓↓

 

0011

0101

-------

0110

 

즉 최종 결과는 6이 된다.

printf("%d\n", 3 ^ 5) //6

 

 

ㄹ) Shift 연산자

 

Shift의 사전적 의미가?

이동이라고 나온다.

 

저 번역처럼 쉬프트 연산자는 비트를 이동시키는 기능을 한다.

 

쉬프트 연산자는 <<, >> 로 두 가지가 있는데

 

<< 는 왼쪽, >>는 오른쪽으로 이동시킨다.

 

 

예를 들어 3은 바이너리로 0011 인데

 

3 << 1을 하면 0011을 왼쪽으로 한 칸 이동시킨다는 의미이다.

 

 

0 0 1 1

이걸 왼쪽으로 이동시키면

0 1 1 0

 

이렇게 된다. (굵은 0은 자리가 이동해서 채워진 비트로, 기본적으로 << 연산자는 빈 자리를 0으로 채운다)

 

즉 3 << 1은 6과 같다.

 

 

그럼 반대로

 

3 >> 2를 하면 왼쪽으로 두 칸 이동하는데

 

왼쪽으로 두 칸 이동하면

0 0 0 0

이 되서 결국엔 결과가 0이 된다. 그런데 >> 연산자는 언제나 0으로 채워지는 것이 아니다.

 

그 이유는 다음 포스팅에서 비트 연산자에 대한 내용을 조금 더 깊게 얘기할 때 다룰 것이다.

 

ㅁ) ~ (NOT) 연산자

~ 은 모든 비트를 반전시켜준다. 0은 1로, 1은 0로 말이다.

 

~3 은 이진법으로 표기했을 때 1100과 같다.

~0 은 이진법으로 표기했을 때 1111과 같다.

~1 은 이진법으로 표기했을 때 1110과 같다.

int a = 3;
~a; // 0011 -->> 1100

 

 

ㅂ)

비트 연산자들도 사칙 대입 연산자처럼

 

대입 연산자와 결합될 수 있습니다.

 

예시는 << 와 | 만 들었지만 다른 연산자들도 원리는 똑같다.

int a = 3;

a <<= 1;//a = a << 1;과 같음
//3 << 1은 6이므로 a = 6이 됨

a = 3;//다시 a = 3
a |= 5;//3 ^ 5가 7이므로 a = 7이 됨 

 

(8) sizeof 연산자

sizeof 연산자는 대상의 size, 크기를 얻을 수 있습니다.

 

sizeof 연산자는 크기를 정수형태로 표현(반환)하는데

 

이때 쓰이는 자료형은 size_t이다.

 

size_t는 별 거 없이 그저 정수형 타입이다. 예를 들어 size_t는 그저 int를 기반으로 tyepdef 된 것인데 typedef는 간단히 말해서 새로운 자료형을 정의할 때 사용된다.

size_t라는 정수형 자료형을 새로 정의한 것이다.

 

 

사용법은 이렇다.

sizeof(int);
sizeof("HelloWorld");
sizeof(30);
sizeof(3.2);
sizeof(3.2f);

첫 강좌에서 HelloWorld를 출력할 때 printf 처럼 ( ) 가 붙는 걸

 

함수라고 했는데 sizeof는 특이하게 함수가 아닌 연산자이다.

 

 

이렇게 자료형을 넣어줄 수도, 값들을 넣어줄 수도 있는데

 

자료형을 넣어준다면 해당 자료형의 크기가, 값을 넣어준다면 그 값의 자료형의 크기를 알 수 있다.

%lu를 쓴 이유는 size_t를 출력하기 위해서이다. size_t는 매번 int인 것이 아니고 컴파일러의 구현마다 다를 수 있다.

 

int 타입의 크기는 32bits, 즉 4Bytes라서 4가 출력됐고

 

30은 정수형이니 기본적을 int로 인식해 4가 출력됐고

 

2.5는 double형으로 인식해 8Bytes,

 

2.5f는 뒤에 f가 붙어 float형으로 인식해 4Bytes가 출력됐다.

 

 

다음 포스팅에서 비트 연산자 중 Shift 연산자에 대해 이어간다.

 

 

 

끝..

728x90

'