C언어 2일차-4

정혜창·2024년 12월 14일

독학

목록 보기
5/28
post-thumbnail

유용한 연산자

형 변환 연산자

형 변환 연산자는 피연산자를 하나 가지며 피연산자의 값을 원하는 형태로 바꾼다. 형 변환 연산자를 사용해서 피연산자의 형태를 바꿀 때는 피연산자의 값을 복사해 일시적으로 형태를 바꾸므로 연산 후 메모리에 남아 있는 피연산자의 형태나 값은 변하지 않는다.

(자료형)피연산자
(double)10 --> 10.0 // (double)a

  • 형 변환 연산자가 필요한 경우
#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바이트)를 연산하면 정수가 실수로 자동 변환되어 연산된다. 하지만 대입 연산은 메모리에 값을 저장하므로 무조건 좌항의 변수형에 맞게 저장된다. 왠만하면 피연산자의 형태를 같게 맞춰 사용하는 편이 좋다.

sizeof 연산자

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

  • sizeof 연산자의 사용 예
#include <stdio.h>

int main(void)
{
	int a = 10;
    double b = 3.4;
    
    printf("int형 변수의 크기 : %d\n", sizeof(a));
    printf("double형 변수의 크기 : %d\n", sizeof(b));
    printf("정수형 상수의 크기 : %d\n", sizeof(10));
    printf("수식의 결과값의 크기 : %d\n", sizeof(1.5 + 3.4));
    printf("char 자료형의 크기 : %d\n", sizeof(char));
    printf("문자열 fruit의 크기 : %d\n", sizeof("fruit"));
    
    return 0;
}

문제없이 실행되지만 경고문이 뜨는데 sizeof 연산의 결과값 형태와 변환문자가 일치하지 않아서 나오는 경고이다. 컴파일러에 따라 다를 수 있으니 무시해도 되지만 경고문이 불편하다면 %d를 %zd로 바꾸면 된다.

sizeof 연산자와 괄호

sizeof는 연산자이므로 기본적으로 괄호가 필요 없지만 계산의 순서를 생각해서 편의상 괄호를 사용하는 경우가 많다. 함수가 아니다 연산자임을 잊지말자.

복합대입 연산자

+=, -=, *=, /=, %= 다섯가지가 있다.

  • 복합대입 연산자
#include <stdio.h>

int main(void)
{
	int a = 10, b = 20;
    int res = 2;
    
    a += 20;				// a와 20을 더한 결과를 다시 a에 저장
    res *= b + 10;			// b + 10을 더한 결과값에 res를 곱하고 다시 res에 저장
    
    printf("a = %d, b = %d\n", a, b);
    printf("res = %d\n", res);
    
    return 0;
}
        

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

콤마 연산자

한번에 여러 개의 수식을 차례로 나열해야 할 때 사용한다. 왼쪽부터 오른쪽으로 차례로 연산을 수행하며 가장 오른쪽의 피연산자가 최종 결과값이 된다.
콤마 연산자는 대입 연산자보다 우선순위가 낮은 유일한 연산자이기 때문에 대입 연산자와 함께 사용할 때는 반드시 괄호가 필요하다.

조건 연산자

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

  • 조건 연산자
#include <stdio.h>

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

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

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

(a > b) ? (res1 = a) : (res2 = b);

일반적으로 조건 연산자를 연산자라고 설명하지만 일치하는 명령어가 있는 것은 아니다. if ~ else문과 동일한 명령으로 번역되므로 연산자보다는 제어문으로 보는 것이 맞다. 다만 수식 형태로도 제어 구조를 사용할 수 있게 해준다.

비트 연산자

비트 연산자는 데이터를 비트 단위로 연산한다. 비트 연산자에는
논리 연산자를 수행하는 &, |, ^ 비트 논리 연산자
비트를 좌우로 움직이는 >>, << 같은 비트 이동 연산자가 있다.
비트 연산자는 데이터를 비트로 정확히 표현할 수 있는 정수에만 사용할 수 있다.

  • 비트 연산식의 결과
#include <stdio.h>

int main(void)
{
	int a = 10;			// 비트열 00000000 00000000 00000000 00001010
    int b = 12;			// 비트열 00000000 00000000 00000000 00001100
    
    printf("a & b : %d\n", a & b);		// a & b : 8
    printf("a ^ b : %d\n", a ^ b);		// a ^ b : 6
    printf("a | b : %d\n", a | b);		// a | b : 14
    printf("~a : %d\n", ~a);			// ~a : -11
    printf("a << 1 : %d\n", a << 1);	// a << 1 : 20
    printf("a >> 2 : %d\n", a >> 2);	// a >> 2 : 2
    
    return 0;
}
	

비트별 논리곱 연산자

& 연산은 두 비트가 모두 1인 경우에만 1로 계산한다.

비트별 배타적 논리합 연산자

^(xor) 연산은 비트 단위로 배타적 논리합 연산을 수행한다.
두 피연산자의 진리값이 서로 다를 때만 참이 된다.(두 비트가 서로 다른 경우에만 1)

비트별 논리합 연산자

| 두 비트 중에서 하나라도 참이면 1로 계산한다.

비트별 부정 연산자

~ 연산은 1을 0으로, 0을 1로 바꾼다. 양수 -> 음수|절대값+1|, 음수 -> 양수|절대값-1|

비트 이동 연산자

<<는 비트를 왼쪽으로 이동 시키고, >>는 오른쪽으로 이동. 밀려나는 비트는 사라지고, 남는 비트는 0으로 채워진다. 만약 음수라면 남는 왼쪽의 남는 비트는 1로 채워진다. 따라서 비트 이동 연산을 수행한 후에도 a의 부호는 바뀌지 않는다. 단, a의 자료형이 unsigned 로 선언되었다면 부호 비트의 의미가 없으므로 왼쪽의 남는 비트는 항상 0으로 채워진다.

  • 비트연산자를 복합대입 연산자로 사용할 수 있을까?
    yes. 예를 들어 a = a << 2; 와 같은 문장을 a <<= 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;				// a의 값을 1증가시키고 3을 곱한다.
    printf("res = %d\n", res);
    res = a > b && a != 5;		// a > b 의 결과와 a != 5의 결과를 && 연산
    printf("res = %d\n", res);
    res = a % 3 == 0;			// a % 3 의 값이 0과 같은지 확인
    printf("res = %d\n", res);
    
    return 0;
}

도전 예제

체중(kg)과 키(cm)를 입력해 BMI(신체질량지수)를 구한 후 BMI의 값이 20.0 이상 25.0 미만이면 "표준입니다" 를 출력하고 그렇지 않으면 "체중관리가 필요합니다"를 출력합니다.

BMI = 체중(kg) / 키^2(m)

내가 한 것

#include <stdio.h>

int main(void)
{
    int kg, cm, det;
    double BMI, c, d;

    printf("당신의 체중과 키를 순서대로 입력해주세요 : ");
    scanf_s("%d %d", &kg, &cm);
    
    c = (double)cm / 100;
    d = c * c;
    BMI =(double)kg / d;
    det = (BMI >= 20.0) && (BMI < 25.0);
    (det == 1)
    	? printf("표준입니다\n")
    	: printf("체중관리가 필요합니다\n");
    
    return 0;
}

해답

#include <stdio.h>

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

회고

처음부터 double 변수로 키, 몸무게를 입력했으면 편했을텐데 괜히 정수형으로 하려다가 변수도 많아지고 복잡해졌다.
변수를 선언할 때 신중하게 해야겠다는 생각이 들었다. 또한 조건 연산자를 씀에 있어서 조건이 참 일때 함수를 써도 되는건 알았지만 연산자 끝났을 때만 ;(세미콜론)을 써야된다는 것을 명심하게 되었다. 아무리 가운데 함수가 있더라도... 세미콜론 쓰지말자 이것때문에 한참을 헤매었다.

profile
Unreal 1기

0개의 댓글