[C] 연산자

JOOYEUN SEO·2023년 8월 8일

C 언어

목록 보기
4/13
post-thumbnail

연산자(operator)는 자료에 대한 여러가지 연산을 수행하도록 하는 기호를 뜻한다.

1. 산술 연산자

(1) 이항 연산자(binary operator)

2개의 자료를 대상으로 산술적인 계산을 수행하는 연산자이다.

연산자기능사용 예시
+ , - , * , /덧셈, 뺄셈, 곱셈, 나눗셈 계산a + 5
%나눗셈의 나머지 계산a % 5

% 연산자는 나머지 연산자(modulo operator)라고도 하며, 실수형 자료에서 사용 불가하고 정수형에서만 가능하다.

⌨️ 예제 1

// 이항 연산자의 사용 예시
#include <stdio.h>

    int main() {
        int a = 7;
        int b = 3;
        
        printf("%d + %d = %d\n", a, b, a + b);
        printf("%d - %d = %d\n", a, b, a - b);
        printf("%d * %d = %d\n", a, b, a * b);
        printf("%d / %d = %d\n", a, b, a / b);  // "정수 ÷ 정수"는 정수 반환(몫 계산 가능)
        printf("%d %% %d = %d\n", a, b, a % b); // "7 ÷ 3"의 나머지 값 계산
        printf("%d %% %d = %d\n", b, a, b % a); // "3 ÷ 7"의 나머지 값 계산
}

🖥️ 실행 결과

7 + 3 = 10
7 - 3 = 4
7 * 3 = 21
7 / 3 = 2
7 % 3 = 1
3 % 7 = 3

(2) 단항 연산자(unary operator)

이항 연산자와 다르게 1개의 자료만을 대상으로 한다. 단항 연산자 중 ++과 --를 증감 연산자라고도 한다.

단항 연산자기능사용 예시
-부호의 반전-5
++1 증가a++, ++a
--1 감소a--, --a

단항연산을 이항연산으로 변경할 수 있다.

  • a++ → a = a + 1
  • a--  → a = a - 1

증감 연산자는 정수형 변수에만 사용되어야 하며, 사용 위치에 따라 전치연산, 후치연산으로 나뉜다.


⌨️ 예제 2

// 전치 증가 연산
#include <stdio.h>

int main() {
    int a = 10, b;
    
    b = ++a;                // 먼저 a에 1을 증가시칸 후, 그 값을 b에 대입
    printf("a : %d\n", a);
    printf("b : %d\n", b);
}

🖥️ 실행 결과

a : 11
b : 11

⌨️ 예제 3

// 후치 증가 연산
#include <stdio.h>

int main() {
    int a = 10, b;
    b = a++;                // 먼저 b에 a 값을 저장한 후, a에 1을 더하기
    printf("a : %d\n", a);
    printf("b : %d\n", b);
}

🖥️ 실행 결과

a : 11
b : 10

위의 후치 증가 연산 예제에서 b = a++; 대신

b = a;	// b에 a 값을 저장
a++;	// a에 1을 더하기

으로 나누어서 작성하면 후치연산을 헷갈리지 않고 직관적으로 볼 수 있다.

2. 대입 연산자(assignment operator)

대입 연산자는 '='을 사용하여 연산자의 오른쪽을 왼쪽에 대입한다. 수식을 압축하여 간단하게 기술할 수 있다.

연산자기능사용 예시
=a에 숫자 n을 대입a = n
+=a = a + n : a에 n을 더한 후 결과를 a에 대입a += n
-=a = a - n : a에 n을 뺀 후 결과를 a에 대입a -= n
*=a = a * n : a에 n을 곱한 후 결과를 a에 대입a *= n
/=a = a / n : a에 n을 나눈 후 결과를 a에 대입a /= n
%=a = a % n : a에 n을 나눈 후 그 나머지를 a에 대입a %= n
&=a = a & n : a와 n에 대해 bit단위의 AND 연산을 한 후 결과를 a에 대입a &= n
|=a = a | n : a와 n에 대해 bit단위의 OR 연산을 한 후 결과를 a에 대입a |= n
^=a = a ^ n : a와 n에 대해 bit단위의 XOR 연산을 한 후 결과를 a에 대입a ^= n

3. 관계 연산자(relational operator)

관계 연산자는 피연산자에 대한 대소 관계를 비교하므로 비교 연산자라고도 하며, 수식의 결과가 참이면 1, 거짓이면 0을 돌려준다.

연산자기능사용 예시
==같은가의 여부를 비교a == b : a와 b는 같다
!=다른가의 여부를 비교a != b : a와 b는 같지 않다
>, >=, <=, <대소 관계를 비교a >= b : a는 b보다 크거나 같다

⌨️ 예제 4

#include <stdio.h>
#include <stdbool.h>	// 부울 자료형을 사용하기 위한 헤더 파일

int main() {
    int a = 2;
    int b = 5;

    bool p = a > b;      // 2 > 5 는 거짓이므로 p = 0
    bool q = a <= b;     // a <= b 는 참이므로 q = 1
    bool r = a == b;     // a == b 는 거짓이므로 r = 0
    
    printf("%d\n", p);
    printf("%d\n", q);
    printf("%d\n", r);
}

🖥️ 실행 결과

0
1
0

4. 논리 연산자(logical operator)

피연산자에 대해 논리연산을 수행하여 결과를 참과 거짓으로 나타내는 연산자다. 논리연산에서 값이 0일 경우에만 거짓이고, 0이 아닌 값은 참이 된다.

연산자기능사용 예시
&&논리곱(AND) : 양쪽 모두 참일 때만 참a && b
||논리합(OR) : 양쪽 중 하나라도 참이면 참a || b
!논리부정(NOT) : 오른쪽이 참이면 거짓, 거짓이면 참!a

⌨️ 예제 5

#include <stdio.h>
#include <stdbool.h>

int main() {
    int a;
    scanf("%d", &a);

    bool p = a >= 1 && a <= 10; // 1 ≤ a ≤ 10 과 같은 의미
    bool q = a == 3 || a == 7;	// 두 조건 중 하나만 참이어도 참
    bool r = !a;                // a가 참이면 r은 거짓, a가 거짓이면 r은 참

    printf("%d\n", p);
    printf("%d\n", q);
    printf("%d\n", r);
}

🖥️ 실행 결과

3  [Enter↵]
1
1
0

5. 조건 연산자(conditional operator)

?와 :를 사용하여 (조건) ? 수식1 : 수식2 의 형식으로 작성한다. 주어진 조건이 참이면 수식1을, 거짓이면 수식2를 수행하는 기능을 갖고 있으며, if문의 기능이 내장된 3항 연산자라고 볼 수 있다.

⌨️ 예제 6

#include <stdio.h>

int main() {
    int a = 3, b, c;
    b = (a > 0) ? (a + 3) : (a + 6);        // 조건을 만족하므로 a + 3 수행
    c = (a > 10) ? (a + 3) : (a + 6);       // 조건을 불만족하므로 a + 6 수행
    printf("b = %d\n", b);
    printf("c = %d\n", c);
}

🖥️ 실행 결과

b = 6
c = 9

6. 비트 연산자(bitwise operator)

비트 연산자는 수치를 2진수로 변환하여 비트(bit) 단위로 하나씩 연산을 수행한다. 정수형 자료에서만 사용 가능한 연산자다.

(1) 논리 비트 연산자

&, |, ~는 각각 논리 연산자의 &&, ||, !와 모양이 비슷하다.

연산자기능사용 예
& (bit AND)대응되는 두 비트가 모두 1일때만 1 반환a & b
| (bit OR)대응되는 두 비트 중 하나라도 1이면 1 반환a | b
^ (bit XOR)대응되는 두 비트가 서로 다를 때만 1 반환a ^ b
~ (bit NOT)1은 0으로, 0은 1로 반환~a

⌨️ 예제 7

#include <stdio.h>

int main() {
    char a = 15, b = 10;

    printf("%d\n", a & b);
    printf("%d\n", a | b);
    printf("%d\n", a ^ b);
    printf("%d\n", ~a);
}

🖥️ 실행 결과

10
15
5
-16

&, |, ^는 2개의 비트값을 맨 앞자리부터 한 비트씩 서로 비교한다. 또한 맨 앞의 비트는 부호를 표시하기 위해 사용하기 때문에, 이 비트가 1일 경우 음수값이 반환된다. ~a의 경우 2의 보수를 사용해서 -16이 출력됐다.

< 변수 a와 b 비트연산 예>

~a :11110000-16
a : 0000111115
b : 0000101010
a&b : 0000101010

(2) 시프트(shift) 비트 연산자

비트를 이동시키는 연산자다. 모든 비트들이 왼쪽 또는 오른쪽으로 n비트씩 이동하며, 맨 왼쪽 또는 오른쪽에 있다가 밀려난 비트들은 버려지고, 밀어내고 난 뒤 비어진 자리는 0으로 채운다.

연산자기능사용 예
<<a 값에 대해 n비트 왼쪽으로 이동a << n
>>a 값에 대해 n비트 오른쪽으로 이동a >> n

⌨️ 예제 8

#include <stdio.h>

int main() {
    char a = 30;             // 00011110(2) → 8bit로 십진수 30 표현
    // 왼쪽으로 이동
    printf("%d\n", a << 1);  // 00111100(2) == 60(10) → 000111100(2)
    printf("%d\n", a << 3);  // 11110000(2) == 240(10) → 00011110000(2)
    printf("%d\n", a << 6);  // 10000000(2) == 128(10) → 00011110000000(2)
    // 오른쪽으로 이동
    printf("%d\n", a >> 1);  // 00001111(2) → 오른쪽으로 이동한 비트는 무조건 잘리게 됨
    printf("%d\n", a >> 3);  // 00000011(2)
    printf("%d\n", a >> 6);  // 00000000(2)
}

🖥️ 실행 결과

60
240
1920
15
3
0

a를 왼쪽으로 3, 6만큼 이동해서 나온 십진수 240, 128은 char형 범위에서 벗어난다. 이럴 경우에는 char형 대신 자동으로 범위에 맞는 int형 등으로 바꿔서 계산된다. 그러면 수용 가능한 비트 수가 더 많아지므로 8bit가 넘어간 비트까지 포함해서 계산할 수 있게 된다. "a << 3"의 경우 잘렸던 비트가 전부 0이어서 앞부분에 포함시켜도 계산값이 달라지지 않지만, "a << 6"은 11110000000이 되어 1920이라는 숫자가 나온다.

7. 기타 연산자

(1) sizeof()

괄호 안에 지정한 자료형, 수식, 변수가 차지하는 기억공간의 크기(byte)를 구하는 연산자다.

⌨️ 예제 9

#include <stdio.h>

int main() {
	// 괄호 안에 자료형을 넣는 경우
    printf("%lu%lu%lu%lu\n", sizeof(int), sizeof(char), sizeof(float), sizeof(double));
    
    // 괄호 안에 변수를 넣는 경우
    int a; char b; float c; double d;
    printf("%lu%lu%lu%lu\n", sizeof(a), sizeof(b), sizeof(c), sizeof(d));
}

🖥️ 실행 결과

4148
4148

sizeof 함수는 unsigned long형으로 출력되기 때문에 %lu를 사용한다.

(2) 형 변환(cast)

cast 연산자를 사용해 임의의 자료에 이미 지정된 자료형을 다른 자료형으로 강제 변환할 수 있다.
'(변환할 자료형)자료' 의 형식으로 사용한다.

⌨️ 예제 10

// 수학, 국어, 영어 3과목 점수의 평균 구하기
#include <stdio.h>

int main() {
    int math = 90, korean = 95, english = 96;
    int sum = math + korean + english;
    double avg = sum / 3;
    printf("%f\n", avg);
}

🖥️ 실행 결과

93.000000

잘못된 값이 출력되는 이유는 sum / 3; 이 "정수 ÷ 정수"이어서 변수 avg 값도 자동으로 정수가 됐기 때문이다.

  • 정수 ÷ 정수 = 정수 (+, -, × 에도 적용)
  • 정수 ÷ 실수 = 정수를 실수로 형변환 하는 것이 좋음
  • 실수 ÷ 정수 = 실수
  • 실수 ÷ 실수 = 실수

→ 정수보다 실수가 더 크기 때문에(더 많은 값 저장 가능) 연산의 결과값은 더 큰 쪽의 자료형이 된다.

이처럼 여러 자료형의 값들이 한 수식에 같이 포함되어 있을 경우, 자동적으로 형 변환이 일어나는 것을 묵시적 형 변환(implicit type conversion)이라고 한다.

🛠️ 코드 수정

#include <stdio.h>
    int main() {
        int math = 90, korean = 95, english = 96;
        int sum = math + korean + english;
        double avg = (double)sum / 3;	// sum이 해당 라인 코드가 실행되는 동안만 실수형 변수로 바뀜
        printf("%f\n", avg);
}

🖥️ 실행 결과

93.666667

변수 sum의 자료형을 double로 변경해도 되지만, 정수값만 저장되는 sum에 실수를 저장할 필요가 없으므로 형변환 연산자를 사용하여 강제로 자료형을 일치시켰다.

(3) 포인터 연산자

& : 주소 연산자로서 피연산자의 주소를 나타냄
* : 내용 연산자로서 피연산자의 내용을 가져옴(특정 주소의 기억공간 안의 내용)
참조 : [C] 포인터




▷ 김형근·곽덕훈·정재화, 『C프로그래밍』, 한국방송통신대학교출판문화원, 2020
▷ 서현우, 『뇌를 자극하는 C 프로그래밍』, 한빛미디어, 2005
▷ 두들낙서, “두들낙서의 C/C++ 강좌”, https://youtube.com/playlist?list=PLlJhQXcLQBJqywc5dweQ75GBRubzPxhAk&si=s8RNpRcpJTi_Lz8M

0개의 댓글