클라이언트/ 서버/ 엔지니어 " 게임 개발자"를 향한 매일의 공부일지

연산자 2 - 그 외 유용한 연산자 본문

프로그래밍 언어/C 언어

연산자 2 - 그 외 유용한 연산자

huenuri 2024. 7. 30. 05:26

연산자 두번째 장으로 기본 연산자 외에 다른 연산들을 학습해보기로 하자. C 언어가 제공하는 효율적이고 특별한 연산자에는 어떤 것이 있는지 알아보고 이를 적재적소에 쓰기 위한 사용법을 배워볼 것이다.

이 연산자는 생김새가 특이하고 사용법도 생소할 수 있다. 조건 연산자처럼 피연산자를 3개 사용하기도 한다.

 

 

1. 형 변환 연산자

 

 

 

 

🎃 형 변환 연산자가 필요한 경우

#include <stdio.h> 
int main(void) 
{ 
  int a = 20, b = 3; 
  double res; 
  res = ((double)a) / ((double)b); 
  printf("a = %d, b = %d\n", a, b); 
  printf("a / b의 결과 : %.1lf\n", res); 
  a = (int)res; 
  printf("(int) %.1lf의 결과 : %d\n", res, a); 
  return 0; 
 }
 

 

처음부터 a와 b를 double형으로 선언하면 편할 듯하지만, double형은 저장 공간이 크고 연산 속도가 느리며 무엇보다 오차가 발생한다. 그렇기에 int형을 기본적으로 사용하고 실수 연산 결과가 필요할 때만 형 변환해서 사용하는 것이 좋다.

실수에서 정수로 형 변환할 때 소수점 이하의 값은 반올림하지 않고 무조건 버린다.

 

 

 

자동 형 변환

컴퓨터는 데이터의 형태에 따라 다른 연산 방법을 사용하므로 펴연산자가 2개 이상이라면 피연산자의 형태는 같아야 한다. 따라서 컴파일러는 컴파일 과정에서 피연산자의 형태가 다르면 형ㄴ태를 일치시키는 작업을 수행한다.

이를 자동 형 변환(또는 암시적 · 묵시적 형 변환)이라고 한다.

이런 형 변환의 기본 규칙은 데이터 크기가 작은 값이 크기가 큰 값으로 바뀌는 것이다. 예를 들어 정수(4바이트)와 실수(8바이트)를 연산하면 정수가 실수로 자동 변환되어 연산된다.

다만 대입연산은 메모리에 값을 저장하므로 무조건 좌항의 변수형에 맞게 저장된다. 자동 형 변환은 형태가 다른 데이터를 자유롭게 연산할 수 있도록 도와주지만, 예상치 못한 값의 변형이 생길 수 있으니 가능하면 피연산자의 현태를 같게 맞춰 주는 편이 좋다.


 

2. sizeof 연산자

 

피연산자를 하나만 사용할 수 있으면 피연산자의 크기를 바이트 단위로 계산해서 알려 준다. sizeof(피연산자)로 표기하며 피연산자의 대상은 변수, 상수, 수식, 자료형 등이 될 수 있다.

  • int형의 크기를 구할 때 : sizeof(int)
  • 상수의 크기를 구할 때 : sizeof(10)

 

🎃 sizeof 연산자의 사용 예

#include <stdio.h> 
int main(void) 
{ 
  int a = 10; 
  double b = 3.4; 
  printf("int형 변수의 크기 : %d\n", (unsigned int)sizeof(a)); 
  printf("double형 변수의 크기 : %d\n", (unsigned int)sizeof(b)); 
  printf("정수형 상수의 크기 : %d\n", (unsigned int)sizeof(10)); 
  printf("수식형 결과값의 크기 : %d\n", (unsigned int)sizeof(1.4 + 3.5)); 
  printf("char 자료형의 크기 : %d\n", (unsigned)sizeof(char)); 
  return 0; 
 }
 

 

sizeof 연산자의 크기를 설정하지 않았더니 계속 경고 표시가 떠서 unsigned int를 추가해주었다.

 

 

 

sizeof 연산자와 괄호

sizeof는 연산자이므로 기본적으로 피연산자에 괄호를 사용할 필요가 없다. 그러나 연산 기호가 있을 경우 결과가 달라진다.

printf("수식형 결과값의 크기 : %d\n", sizeof 1.4 + 3.5);

 

sizeof 연산자는 1.5만 두고 계산(1차 연산)해서 8을 계산한다. 거기에 3.4가 더해서(2차 연산) 결과값이 11.4가 된다.

또 char형 변수 선언문으로 인식되어 에러가 발생한다.

 


 

 

3. 복합대입 연산자

 

대입연산자(=)와 증감 연산자(++, --)를 제외한 다른 연산자는 연산하고 나서 피연산자의 값을 바꾸지 않는다. 만약 연산 결과를 피연산자에 저장할 필요가 있다면 추가로 대입 연산을 수행해야 한다.

이때 복합대입 연산자를 사용하면 간편하다.

복합대입연산자는 연산 결과를 다시 피연산자에 저장한다.

 

 

 

🎃 복합대입 연산자

#include <stdio.h> 
int main(void) 
{ 
  int a = 10, b = 20; 
  int res = 2; 
  a += 20; 
  res *= b + 10; 
  printf("a = %d, b = %d\n", a, b); 
  printf("res = %d\n", res); 
  return 0; 
 }

 

 

복합대입 연산자는 대입 연산자의 특징을 그대로 가진다

  • 왼쪽 피연산자는 반드시 변수가 와야 한다.
  • 오른쪽 항의 계산이 모두 끝난 후, 즉 가장 마지막에 복합대입 연산자를 계산한다.

복합대입 연산자는 저장되는 공간과 연산되는 공간이 다르다는 개념을 이해해야 한다

 


 

 

 

4. 콤마 연산자

한꺼번에 여러 개의 수식을 차례로 나열해야 할 때 사용한다. 콤마 연산자는 왼쪽부터 오른쪽으로 차례로 연산을 수행하며 가장 오른쪽의 피연산자가 최종 결과값이 된다.

 

 

🎃 콤마 연산자

#include <stdio.h> 
int main(void) 
{ 
  int a = 10, b = 20; 
  int res; 
  res = (++a, ++b); 
  printf("a: %d, b: %d\n", a, b); 
  printf("res: %d\n", res); 
  return 0; 
 }

 

 

콤마 연산자는 대입 연산자보다 우선순위가 낮은 유일한 연산자이다. 따라서 대입 연산자와 함께 사용할 때는 반드시 괄호가 필요하다.

 

괄호가 빠졌을 경우

 

 

콤마 연산자는 제어문에서 조건식을 나열하는 괄호 안과 같이 세미콜론 사용이 불가능한 구조에서 사용한다.

 


 

 

 

 

5. 조건 연산자

 

조건 연산자는 유일한 삼항 연산자로 ?와 : 기호를 함께 사용해 표현된다. 조건 연산자는 첫번째 피연산자가 참이면 두번째 피연산자가 결과값이 되고, 첫번째 피연산자가 거짓이면 세번째 피연산자가 결과값이 된다.

 

 

 

🎃 조건 연산자

#include <stdio.h> 
int main(void) 
{ 
  int a = 10, b = 20, res; 
  res = (a > b) ? a : b; 
  printf("큰 값 : %d\n", res); 
  return 0; 
 }

 

 

조건 연산자의 피연산자에 대입식 사용하기

조건 연산자의 피연산자에 대입식을 직접 사용할 수도 있다.

 

 

기존 코드

res = (a > b) ? a : b;

 

피연산자에 대입식을 넣은 코드

(a > b) ? (res = a) : (res = b);

 

하지만 이 경우에는 res=를 중복해서 사용하므로 바람직한 사용법은 아니다.

이런 표기법은 (a > b) ? (res1 = a) : (res2 = b); 처럼 참일 때와 거짓일 때 그 결과를 반영하는 대상이 다를 경우 유용하다.

조건 연산자는 코드를 간략히 만들어 주는 효과가 있으며 매크로 함수에 사용하면 좋으나 가독성을 떨어뜨릴 가능성이 있으므로 필요한 곳에만 사용하는 것이 좋다.

 


 

 

 

6. 비트 연산자

비트 연산자는 데이터를 비트 단위로 연산한다. 비트 연산ㅈ가에는 논리 연산을 수행하는 &, |, ^ 같은 비트 논리 연산자와 비트를 좌우로 움직이는 >>, << 같은 비트 이동 연산자가 있다.

비트 연산자는 데이터를 비트로 정확히 표현할 수 있는 정수에만 사용할 수 있다.

 

 

🎃 비트 연산식의 결과

#include <stdio.h> 
int main(void) 
{ 
  int a = 10; int b = 12; 
  printf("a & b : %d\n", a & b); 
  printf("a ^ b : %d\n", a ^ b); 
  printf("a | b : %d\n", a | b); 
  printf("~a : %d\n", ~a); 
  printf("a << 1 : %d\n", a << 1); 
  printf("a >> 2 : %d\n", a >> 2); 
  return 0; 
 }

 

 

 

비트 논리 연산자

 

 

 

 

 

 

 

비트 이동 연산자

<<은 비트를 왼쪽으로 이동시키고, >>은 오른쪽으로 이동시킨다. 이때 왼쪽으로 밀려나는 비트는 사라지고 오른쪽의 남는 비트는 0으로 채워진다.

반대로 오른쪽 비트 연산을 수행하면 2로 나눈 몫이 되는데 이때 오른쪽으로 밀려나는 비트는 사라지며, 왼쪽의 남는 비트는 부호 비트로 채워진다.

 

 

a에 비트 이동 연산을 수행한 후에도 a의 부호는 변하지 않는다. 단, a의 자료형이 unsigned로 선언되었다면 부호 비트의 의미가 없으므로 왼쪽의 남는 비트는 항상 0으로 채워진다.

 


 

 

 

 

7. 연산자 우선순위와 연산 방향

하나의 수식에서 2개 이상의 연산자가 함께 쓰일 때는 연산자의 우선순위에 따라 연산된다. 큰 흐름에 따라 요약하면 다음과 같다.

 

 

🎃 연산자 우선순위와 연산 방향

#include <stdio.h> 
int main(void) 
{ 
  int a = 10, b = 5; 
  int res; 
  res = a / b * 2; 
  printf("res = %d\n", res); 
  res = ++a * 3; 
  printf("res = %d\n", res); 
  res = a > b && a != 5; 
  printf("res = %d\n", res); 
  res = a % 3 == 0; 
  printf("res = %d\n", res); 
  return 0; 
 }
 

 

 

 

연산자의 종류는 굉장히 많다. 그 많은 연산자의 연산 순서를 줄줄이 외우고 다니는 일은 쉽지 않다. 따라서 여러 연산자를 함께 사용할 때 의심되거나 분석이 까다롭다고 느껴진다면 주저 없이 괄호를 사용하면 된다.

 


 

 

 

학습 내용 정리

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

연습문제 풀기

 

👌 문제 1

 

short형과 long형의 자료형 크기를 비교해 크기가 큰 자료형이 무엇인지 출력하는 프로그램을 완성하시오.

#include <stdio.h> 
int main(void) 
{ 
  int res; 
  res = sizeof(short) > sizeof(long); 
  printf("%s\n", (res == 1) ? "short" : "long"); 
  return 0; 
 }

short형의 크기가 long형 보다 크면 참이므로 1, 그렇지 않으면 0을 res에 저장한다.

res가 1과 같으면 short형의 크기가 크므로 출력하고 그렇지 않으면 long형을 출력한다.

 

 

 

👌 문제 2

 

야구 경기장의 좌석수가 70개이고, 입장객 수가 65명일때, 입장률을 표시하는 프로그램을 만드시오.

#include <stdio.h> 
int main(void) 
{ 
  int seats = 70; 
  int audience = 65; 
  double rate; 
  rate = audience / (double)seats * 100; 
  printf("입장률 : %.1lf\n", rate); 
  return 0; 
 }
 

 

형 변환을 하여 입장률을 계산했다.

 

 

 

 

👌 문제 3

 

3.76시간은 몇 시간, 몇 분, 몇 초인지 출력하는 프로그램을 만드시오.

#include <stdio.h> 
int main(void) 
{ 
  int hour, min, sec; 
  double time = 3.76; 
  hour = (int)time; 
  time -= hour; 
  time *= 60.0; 
  min = (int)time; 
  time -= min; 
  time *= 60.0; 
  sec = (int)time; 
  printf("3.76시간은 %d시간 %d분 %d초입니다.\n", hour, min, sec); 
  return 0; 
 }
 

 

이 문제는 다시 풀어봐도 여전히 어려워서 다음에 한번 더 풀어봐야 할 것 같다. 어디에 담고 얼마를 곱해서 초를 분, 시간으로 바꾸는 것이 어려웠다.

 

 

 

 

👌 문제 4

 

체중과 키를 입력해 BMI를 구한 후 BMI의 값이 20.0 이상 25.0 미만이면 “표준입니다”를 출력하고, 그렇지 않으면 “체중관리가 필요합니다”를 출력하는 체중관리 프로그램을 만드시오.

 
#include <stdio.h> 
int main(void) 
{ 
  double weight, height; 
  double bmi; 
  printf("몸무게(kg)와 키(cm) 입력 : "); 
  scanf_s("%lf%lf", &weight, &height); 
  bmi = (height * height) / weight; 
  printf("%s\n", (bmi >= 20.0) && (bmi < 25.0) ? "표준입니다" : "체중관리가 필요합니다"); 
  return 0; 
 }
 

이 문제는 처음에는 정말 어려워서 저자 게시판에 질문도 남겼으나 해결하지 못했었다. 근데 이번에 공부하면서 이 문제가 쉬워졌다. 코딩테스트에서 비슷한 문제를 많이 풀었더니 이젠 이런 문제쯤은 식은 죽 먹기다.

 


 

 

오늘의 학습을 마치고

 

드디어 4단원 학습을 마쳤다. 4단원은 분량이 정말 많아서 아침에 3시간으로도 부족했다. 점심식사 후에 나머지 내용을 정리하고 연습문제를 풀어보았다.

오늘은 시간이 없어 코딩 테스트 문제는 풀지 못할 것 같다. 내일은 다음 단원 내용 정리는 하지 않고, 조건문에 관한 문제만 풀어볼 예정이다~

지난번에 형 변환으로 해서 나눗셈 연산을 하는 문제를 계속 틀리고 무척 어려웠는데 이제는 풀 수 있을 것 같다.