IT 정보/C언어

[C프로그래밍/C/C언어]연산자

김윤석 2007. 12. 17. 16:23

[C프로그래밍/C/C언어]연산자




연산자
§ 학습목표

  1. 연산자의 종류를 안다.
  2. 연산자의 우선순위를 안다.
  3. 연산자의 특성을 알고 설명할 수 있다.


1. 연산자

연산자란 프로그램에서 연산을 가능하게 만들어 준다. 이는 대상 자료에 대해 어떤 조작을 하는 부호이다. 이때 대상이 되는 자료들 오퍼랜드(Operand)라 하고 연산자를 오퍼래이터(Operator)라고 한다.

연산의 대상이 되는 오퍼랜드의 개수에 따라 C의 연산자는 1항 연산자, 2항 연산자, 3항 연산자 등으로 구분한다.

그리고 각 연산자들은 우선 순위라는 게 있어 한 문장에서 여럿의 연산자들이 쓰였을 때 그 우선순위에 의거하여 연산을 수행하게끔 되어 있다. 동일한 우선순위의 연산자들이 한 수식에 동시에 쓰였을 경우에는, 이 식을 좌측부터 평가하느냐 우측부터 평가하느냐에 따라 좌결합성과 우결합성으로 나누어 지는 성질을 가지는 것도 있다.(복잡하져?? -_-;;)

조금 복잡하겠지만 일단 익혀두면 복잡한 알고리즘도 쉽고 함축성 있게 표현할 수 있어 유용하다.

2. 연산자의 종류와 우선순위

대분류
소분류
연산자
결합규칙
우선순위
일 차 식 primery ( ) [ ] -> .
-->
높음
단항 연산자 단항 ! ~ ++ -- - cast연산자 * & sizeof
<--
 
이항 연산자 승제 * / %
-->
 
가감 + -
-->
 
쉬프트 << >>
-->
 
비교 < <= > >=
-->
 
등 가 == !=
-->
 
비트AND &
-->
 
비트XOR ^
-->
 
비트 OR |
-->
 
논리AND &&
-->
 
논리 OR ||
-->
 
삼항 연산자 조 건 ? :
<--
 
치환 연산자   = += -= *= /= %=
<--
 
  >>= <<= &= ^= !=
<--
 
순차 연산자 순 차 ,
-->
낮음

연산순위개념이 없는 #, ##, defined등 3개의 전처리기 연산자가 또 있다.

3. 산술연산자

1) + : 오른쪽에 있는 값을 왼쪽에 있는 값에 더한다.

2) - : 왼쪽에 있는 값에서 오른쪽의 값을 뺀다.

3) * : 오른쪽의 수를 왼쪽의 수로 곱한다.

4) / : 왼쪽의 수를 오른쪽의 수로 나눈다. 정수와 정수 의 연산일 땐,소수점 이하는 버린다.

5) % : 왼쪽의 수를 오른쪽의 수로 나눌 때 나머지를 결 과로 취한다. (정수에서만 사용)

6) ++ : 오른쪽이나 왼쪽에 있는 변수의 값을 하나 증가 시킨다.

7) -- : 오른쪽이나 왼쪽에 있는 변수의 값을 하나 감소 시킨다.

6)과 7)은 따로 증감연산자라고도 한다.

4. 증감연산자

일단 다음의 예제를 입력하고 실행해 보자

<리스트1>
#include <stdio.h>
#include <conio.h>
main()
{
    int a = 1, b = 1;
    int aplus, plusb;

    aplus = a++;
    plusb = ++b;
    printf("   A   Aplus   B   plusB\n");
    printf(" %3d %5d %5d %5d\n",a,aplus,b,plusb);
    getch();
}


결과는 다음과 같다.


1) aplus = a++; 후위형 : a가 사용된 후, a의 값이 하나 증가한다.
2) plusb = ++b; 전위형 : b의 값이 하나 증가한 후, b가 사용된다.

다음예를 보고 어떤 경과가 나올지 한번 생각해 보자. while문이 사용되었지만 일단 제쳐 두소, num=5일때 어던 결과가 나올지만 생각해 보자.

while (num<21) {
/* num이 5일때, 어떤 값이 나올까? */
printf(%d %d\n", num, num*num++);
}

이 식을 보면, 5 25를 찍고, num을 6으로 증가시키는 자연스러운 식처럼 보이지만, 실제로 실행결과는 6 25가 찍힌다. 왜냐하면 printf()함수는 마지막 인자부터 먼저 넘긴다는 오묘한 진리가 있다.

ans = num/2 + 5*(1 + num++);

보통, num/2가 먼저 계산이 된다고 믿고 싶으나, 실제로는 먼저 num이 증가하고 나서 num/2에 사용된다. () 때문이다.


5. 치환(대입) 연산자

치환 또는 대입연산자는 +=, -=, *=, /=, %=, &=, |=, =, >>=, <<= 등이 있다.

대입 연산자라고 하는 이러한 연산자들은 모두 =와 결합되어서 식의 복잡성을 줄여준다.

x += 3; 은 x = x + 3; 과 같다.

x *= y + 1; 은 x = x * (y + 1); 과 같다.

x += y += z = 1; 은 z=1; y=y+z; x=x+y 와 같다.

1) 단순치환

a=b;

2) 다중치환

a=b=c=d;

3) 복합치환 : a += b;

다중 치환의 경우에는 식을 우측에서 평가하여 좌측의 변수로 차례대로 치환하게 된다.(우결합성)

a = b = c = d = 1; 은 a = ( b = ( c = ( d = 1 ))); 과 같으며, d=1;c=d;b=c;a=b; 와 같다.

a = b*c = d*e = 1; 은 e=1; c=d*e; a=b*c; 과 같다.

6. 관계 연산자

관계연산자는 <, >, <=, >=, ==, != 등이 있다.

자료의 크기 등을 판단할 때 사용하는 연산자로 식의 값이 참이면 1, 거짓이면 0의 값을 갖는다.

<=, >=는 부호의 순서가 바뀌면 안된다.

==, !=는 다른 관계 연산자들보다 우선순위가 낮다.

초보자들은 ==을 쓴다는 게 그만 =(대입연산자)를 쓰는 경우가 있다.(조심!)

(1) a < b < c 의 평가 과정

1) a < b 이면 참(1)이므로 1, (a<b)<c이면 1(참)이 된다.

2) a < b 가 아니면 거짓(0)이 되므로 0, (a>=b)<c이면 1(참) 이 된다. 그 외의 경우는 모두 0이다.

(2) 산술연산자와 관계연산자의 우선순위

x > y + 2 는 관계 연산자들의 우선순위가 산술 연산자들보다 낮으므로 ( x > y ) + 2 가 아니라, x > (y+2) 와 같다. 그리고 관계 연산자들은 좌결합성을 가지므로 ex != wye == zee 는 실제로는 ( ex != wye ) == zee 와 같다.

(3) 주의사항

처음에는 그냥 지나치기 쉬우나, 좌결합성이냐 우결합성이냐와 연산자들의 우선 순위는 중요하므로 잘 알아두자. 만일 마냥 헷갈린다면, ( )를 십분 활용하여 에러의 소지를 없앨 필요가 있다.

7. 논리 연산자

!, &&, || 의 3가지 연산자가 있다.

(1) 논리부정 연산자(NOT)

식의 값이 0(거짓)이면 '!식'의 값은 1(참)이 되고 식의 값이 참이면 거짓이 된다.

(2) 논리곱 연산자(AND &&)

여러 식중 한개라도 거짓의 값이 있으면 거짓이 된다.

(3) 논리합 연산자(OR ||)

여러 식중 한개라도 참이면 참의 값을 가지게 된다.

(4) 기본 진리값

A
B
A && B
A || B
!A
!B
0
0
0
0
1
1
0
1
0
1
1
0
1
0
0
1
0
1
1
1
1
1
0
0


다음과 같은 경우를 생각해 보자.

(cat > rat) && ( debt == 100 ) 은 두 식이 모두 참이어야 참이 된다.
(cat > rat) || ( debt == 100 ) 은 둘 중 하나만 참이어도 참이 된다.

5>2 && 4>7 은 하나만 참이므로 거짓이다.
5>2 || 4>7 은 둘 중 하나가 참이므로 참이 된다.
!(4>7)은 4>7이 거짓이므로 참이 된다.

<예제2> x에 관한 여러 수식이 주어져 있다. 각 식의 x의 값이 어떻게 수행 되는 지 예측해 보라.
<리스트2>
#include <stdio.h>
main()
{
    int x, y, z;
    x = 1, y = 2, z = 4;
    x = x || y && z;
    printf("%d\n",x);
    x = 1, y = 2, z = 3;
    x = (x > y || z ==y && x<z);
    printf("%d\n",x);
    x = y = z = 1;
    x = -y++ + ++z;
    printf("%d\n%d\n%d\n",x,y,z);
}

실행결과는 1 0 1 2 2이다. 예상결과와 맞았는가?
4,5,6행에서 6행은 우선순위에 의거하면 x = (x ||(y && z)); 로 괄호를 칠 수가 있다. 여기에 수를 대입해 보면, x = (1 ||(2 && 3)) = (1 || 1)= 1이 된다. (C에서는 식의 값이 0이 아닐 때는 모두 참으로 간주한다)
8,9,10행에서 9행을 우선순위에 의거하여 괄호를 쳐 보면, x = (x > y)||(z == y) && (x < z))와 같다. 여기에 수를 대입해 보면 결과는 0이 된다.
11,12,13행에서 12행은 x = -( y++ ) + ( ++z ) = -(1)+(2) 로서 x=1, y=2, z=2가 된다.

자세히 꼼꼼히 따져 보기를 바란다.

8. 비트 연산자

비트조작을 위해 쓰이는 연산자이다. 주의할점은 오퍼랜드는 정수 또는 정수형변수라야 한다.

(1) 비트합 연산자(OR- |)

좌우의 식을 이진수로 하는 비트합을 구해준다.

a = 117, b = 216일 때 a|b의 결과

117 => 0000 0000 0111 0101
216 => 0000 0000 1101 1000
============================
          0000 0000 1111 1101 => 253

비트합 연산자의 용도는 바로 특정한 비트를 1로 세트시킬때 이용된다.

a = 117때 상위 4비트를 1로 한다.
117 => 0000 0000 0111 0101
          1111 0000 0000 0000
============================
          1111 0000 0111 0101 => 1로 세트하려는 부분만 1로, 나머지는 0으로한다.

(2) 비트곱 연산자(AND- &)

좌우의 식을 2진수로 하는 비트곱을 구해준다.

a = 117, b = 216일 때 a&b의 결과
117 => 0000 0000 0111 0101
216 => 0000 0000 1101 1000
============================
          0000 0000 0101 0000 => 80

비트곱 연산자의 용도는 특정 비트를 0의로 리셋하려는 경우에 이용된다.

a = 44149일 때 상위 4비트를 0으로 한다.
44149 => 1010 1100 0111 0101
             0000 1111 1111 1111
==============================
             0000 1100 0111 0101 => 0으로 리셋하려는 부분만 0으로, 나머지는 1로 한다.

(3) 배타적 논리합 연산자(XOR- ^)

좌우의 식을 2진수로 하는 배타적논리합을 구한다.

a = 117, b = 216일 때 a^b의 결과

117 => 0000 0000 0111 0101
216 => 0000 0000 1101 1000
============================
          0000 0000 1010 1101 => 173

두 개의 비트가 동일하면 0, 다르면 1이 된다.

(4) 비트반전 연산자(NOT- ~)

~는 부호를 반전하는 연산자로서 비트1은 0으로, 0은 1로 만든다. (1의 보수 연산자라고도 한다)

a = 117일 때 ~a의 결과

117 => 0000 0000 0111 0101
============================
          1111 1111 1000 1010 => -118

(5) shift 연산자( <<,>> )

좌측 식의 결과를 우측식만큼 비트를 이동시킨다. 이 때 밀리는 쪽의 맨 끝 비트는 밀려나오고, 반대쪽이 마지막 비트는 보통0으로 채워진다.

C언어에서는 컴퓨터의 기종이나 컴퍼일러에 따라 약간 다르다. 보통 좌측으로 쉬프트한 경우에는 맨 우측에 무조건 0이 채워지지만 우측으로 쉬프트한 경우에는 부호가 없는 정수이거나 맨 좌측의 비트가 0(양수)이면 0을 채우고, 부호가 있는 정수이고 맨 좌측의 비트가 1(음수)일 때는 1을 채운다. 즉, 쓸데 없이 부호를 바꾸지 않는다고 볼 수 있다.

a = 117일 때 a << 2 의 결과

117 => 0000 0000 0111 0101
============================
      00 0000 0001 1101 0100 <= 00

또한 비트 연산자는 등호와 결합해서 치환 연산자를 이룰 수 있다.
a = a >> b; 는 a >>= b, a = a & b; 는 a &= b와 같다.

9. 순차 연산자(,)-comma연산자

여러개의 식을 한 줄에 나열하는 기능을 가지고 있다.

우선 순위가 가장 낮으며, 좌결합성을 가지며, 컴머 우측에 있는 식을 평가하여 얻은 값을 결과로 한다.

아래의 예를 보면서 이해 하도록 하자.

x = (y = 1, y++); 는 x = 2, y = 2 가 된다.

x = (y = 1, ++y); 는 y = 1, x = ++y이므로 x = 2, y = 2가 된다.

x = (y = 1, y+1); 은 y = 1, x = y+1이므로 x = 2, y = 1이 된다.

x = (y = 1, z = 2); 는 y = 1, z = 2, x = 2가 된다.

x = (y = 3, y+2); 는 y = 3, x = 5가 된다.

<예제3> 아래 프로그램에서 x와 y의 값은 어떤 결과가 나오겠는가?

<리스트3>
#include <stdio.h>
main()
{
    int i,j;
    i = (j = 15, j+4);
    printf("i = %d, j = %d\n",i,j);
}

10. 삼항 연산자

형태는 '식1 ? 식2 : 식3 '의 모양을 가지고 있다.

식1을 평가하여 참(1)이면 식2의 값을, 거짓(0)이면 식3의 값을 가진다

우결합성을 가지므로 여러번 기술하였을 때는 맨 우측부터 평가된다.

<예제4>

if (a > b) c = a;
else c = b;

를 조건연산자로 구현하여라. 또, a=1,b=2일 때 조건 연산을 행한 뒤 a, b, c의 값은 어떻게 되겠는가?

<리스트4>
#include <stdio.h>
main()
{
    int a,b,c;
    a = 1;
    b = 2;
    c = (a > b) ? a:b;
    printf("a %d b %d c %d\n",a,b,c);
}


x = (y > z) ? 1 : (y < z) ? 2 : 3;은 다음과 같다.

i) y > z 이면 x = 1이 된다.
ii) y > z가 아니면 y < z를 평가한다. y < z이면 x = 2가 된다.
iii) i) ii) 둘다 아니면 x = 3 이 된다.
위의 식을 if - else문으로 고치면 아래와 같다.

if (y > z) x = 1;
else if (y < z) x = 2;
else x = 3;




출처 : http://www.it-bank.or.kr/prom/c_main.htm