Part 06 세상을 변화시키는 연산자 안산1대학 디지털정보통신과 임 성 국
이 장의 내용 대입문도 사실은 수식이다 대입연산자의 변형 증감연산자 조건연산자 괄호도 연산자인가? 우선순위와 결합 순서 정리
6.1 대입문도 사실은 수식이다
대입문 변수에 값을 대입시키는 문장 대입문 동작 과정 a = a + 1; "a와 a+1이 같다"는 뜻이 아니라 부수효과(side effect) 연산자나 함수가 값을 리턴(return)하는 것 외에도—변수 값을 변경시키는 등—부수적으로 발생시키는 효과
대입 수식 대입연산자 = 연속 대입 대입연산자(assignment operator) =도 엄연한 연산자이므로 값을 돌려준다. 대입연산의 결과 값은 해당 변수에 저장된 값이다. 연속 대입 대입연산 결과를 이용하면 연속 대입(cascading assignment) 연산을 수행할 수 있다. = b = a = 2; // b = (a = 2);와 같은 의미
assignment.c 실행결과: 초기의 a와 b 값입니다. a = 0, b = 0 a = a + 1; 을 수행했습니다.
6.2 대입연산자의 변형
누적대입 연산자 누적대입 연산자 형태 누적대입 연산자가 꼭 필요한가? 누적대입 연산자의 ◎로 사용할 수 없는 연산자 변수 ◎= 수식 여기서 ◎는 이항연산자이며 위 수식의 의미는 다음 수식과 같은 의미임 변수 = 변수 ◎ (수식) 누적대입 연산자가 꼭 필요한가? 꼭 필요하지는 않음… 그럼 왜? 간결하기 때문 '변수'에 해당하는 좌변이 복잡할 경우 유리함 yyval[yypv[p3+p4]+yypv[p1+p2]] += 2; 누적대입 연산자의 ◎로 사용할 수 없는 연산자 크기 비교 연산자 <와 > 왜 그럴까요? C의 철학 C 언어의 설계 철학은 간결성이다.
assignment2.c 실행결과: 초기의 a 값입니다. a = 0 a += 1; 을 수행했습니다. a = 1
6.3 증감연산자
증감연산자 증가연산자 감소연산자 전치와 후치 피연산자의 값을 하나 증가시킴 a++; 는 a += 1;과 같은 의미 피연산자의 값을 하나 감소시킴 a--; 는 a -= 1;과 같은 의미 전치와 후치 증감연산자는 전치, 후치에 따라 돌려주는 값이 달라진다. 후치일 경우(a++ 혹은 a--)에는 증감 이전 변수 값이 돌려주는 값이다. 전치일 경우(++a 혹은 --a)에는 증감 이후 변수 값이 돌려주는 값이다.
증가연산자 전치와 후치 비교 초기 a, b 값이 5일 때, 후치와 전치 비교 후치 전치 단계 수행연산 수식 a 값 b 값 N/A b = 2 * a++ 5 1 ++ b = 2 * 5 6 2 * b = 10 3 = 10 단계 수행연산 수식 a 값 b 값 N/A b = 2 * ++a 5 1 ++ b = 2 * 6 6 2 * b = 12 3 = 12
incr.c 실행결과: 초기의 a와 b 값입니다. a = 5, b = 5 b = 2 * a++; 를 수행했습니다.
김소연산자 전치와 후치 비교 초기 a, b 값이 5일 때, 후치와 전치 비교 후치 전치 단계 수행연산 수식 a 값 b 값 N/A b = 2 * a-- 5 1 -- b = 2 * 5 4 2 * b = 10 3 = 10 단계 수행연산 수식 a 값 b 값 N/A b = 2 * --a 5 1 -- b = 2 * 4 4 2 * b = 8 3 = 8
decr.c 실행결과: 초기의 a와 b 값입니다. a = 5, b = 5 b = 2 * --a; 를 수행했습니다.
증감연산자에 관한 조언 증감연산자 사용 이유 증감연산자에 관한 조언 오용 예: a에 5가 저장되어 있을 때 다음 수식의 값은? 증감연산자를 사용하는 단 하나의 목적은 "간결하기 때문" 간결성 때문에 정확성을 무너뜨린다면 어리석은 짓 증감연산자에 관한 조언 하나의 수식에 여러 번 사용되는 변수에는 증감연산자를 사용하지 말라 오용 예: a에 5가 저장되어 있을 때 다음 수식의 값은? ++ a * a ++
6.4 조건연산자
조건연산자 유일한 3항 연산자 사용 예 조언 형식: 조건 ? 수식1 : 수식 2 의미: '조건'이 참이면 '수식1' 값을, 거짓이면 '수식2' 값을 돌려줌 사용 예 max = a > b ? a : b; a > b이면 max = a; 그렇지 않으면 max = b; 조언 조건을 괄호로 감싸면 더 이해하기 쉬움 max = (a > b)? a: b;
조건연산자에서 단락회로 계산 단락회로 계산 단락회로 계산 예 조건연산자의 피연산자는 필요할 때만 계산된다. 이를 단락회로 계산(short-circuit evaluation; 지름길 계산)이라고 한다. 단락회로 계산 예 (n != 0) sum / n: 1 위 수식에서 조건연산자의 피연산자는 다음 세 가지 n != 0 sum / n 1 n이 0이면 sum / n은 계산되지 않으므로 오류가 아님 (n != 0) 1: sum / n으로 작성했다면 '0으로 나눔' 오류
조건연산자의 조건 결과 값 수식 자료형 일치 자료형 불일치 예 a ? b: c에서 b와 c의 자료형이 같아야 함 자료형이 다를 경우 자동 형 변환이 수행됨 자료형 불일치 예 c ? 1: 3.14; 결과 값은 1 또는 3.14 중 하나임 1은 int형, 3.14는 double형이므로 자료형이 일치하지 않는다. int형 1을 double형 1.0으로 형증진(type promotion) 수행 따라서 c가 참일 경우의 값은 int형 1이 아니라 double형 1.0이다.
6.5 괄호도 연산자인가?
괄호도 연산자인가? 연산자가 아닌 괄호 ( ) 연산자로 사용되는 괄호 ( ) 연산자 피연산자의 관계를 나타내기 위한 괄호는 연산자가 아님 (n != 0)? sum / n: 1 괄호로 묶은 수식을 가장 먼저 계산한다? … 꼭 그런 것은 아님 n != 0? (sum / n): 1 연산자로 사용되는 괄호 ( ) 함수 호출 연산에 사용된 괄호 printf("%d", n); 형변환 연산에 사용된 괄호 avr = sum / (double) n; avr = sum / ((double) n);
6.6 우선순위와 결합순서 정리
우선순위와 결합순서 정리 함수 호출 연산자 형변환 연산자
우선순위와 결합순서 기억 요령 일반 법칙 최고 우선순위와 최저 우선순위는 기억하자 곱은 합보다 우선한다. 단항연산자와 대입연산자의 결합순서는 우측에서 좌측이다. 최고 우선순위와 최저 우선순위는 기억하자 최고 우선순위: () [] -> . 최저 우선순위: 콤마 연산자 , 나머지는 "계산하여 비교한 뒤, 판단하여 저장한다"
계산순서에 관한 주의사항 우선순위/결합순서와 계산 순서는 다르다 피연산자의 계산 순서는 정의되지 않은 경우가 많음 우선순위/결합방향은 먼저 계산한다는 의미가 아님 괄호로 묶었다고 해서 먼저 계산된다는 의미도 아님 피연산자의 계산 순서는 정의되지 않은 경우가 많음 예외: 단락회로 계산 연산자 && || ?: , +의 계산 순서 x = f() + g(); f가 먼저 호출된다는 보장이 없음 함수 인수 계산 순서 printf("%d %d\n", ++n, power(2, n)); ++n이 먼저 수행된다는 보장이 없음
여러 의미로 사용되는 연산 기호 +, -, *, & 등은 단항일 때, 이항일 때 의미가 다름
Key Point
Key Point 1 연산자의 부수효과란 연산자가 값을 돌려주는 것 외에 부수적으로 발생시키는 효과다. 대입 연산자는 변수에 값을 저장하는 부수효과를 발생시킬 뿐만 아니라 변수에 저장된 값을 돌려준다. 누적대입 연산자 ◎=(여기서 ◎는 이항 연산자)를 이용한 수식 a ◎= b는 a = a ◎ (b)와 같은 의미다. 누적대입 연산자는 좌변이 매우 복잡할 경우에 특히 유용하다. 증감 연산자는 변수의 값을 1만큼 증가시키거나 감소시킬 때 사용한다. 변수 a의 값을 1 증가시키려면 a++나 ++a를 사용하고 1 감소시키려면 a--나 --a를 사용한다. 증감 연산자는 전치로 사용했을 경우와 후치로 사용했을 경우에 결과 값이 다르다. 전치로 사용하면 증감된 후의 값이 결과 값이 되며 후치로 사용하면 증감되기 전의 값이 결과 값이 된다.
Key Point 2 조건 연산자 ?:는 피연산자를 세 개 받는 삼항 연산자이다. 조건 연산자를 사용한 수식 a?b:c의 값은 a가 참(a≠0)일 때 b가 되고 a가 거짓(a=0)일 때 c가 된다. 조건 연산자도 단락회로 계산을 이용한다. 즉 조건 연산자의 두 번째 피연산자와 세 번째 피연산자 중 하나는 계산되지 않는다. 연산자의 적용 범위를 명시하기 위한 괄호는 연산자가 아니다. 괄호가 연산자로 사용되는 경우는 형 변환 연산자나 함수호출 연산자의 경우뿐이다. 함수호출 연산자와 멤버 추출 연산자([], ., ->)가 가장 우선순위가 높다. 나머지 연산자 중에서는 단항 연산자가 이항 연산자보다 우선순위가 높다. 같은 부류의 이항 연산자들 사이에서는 곱에 해당하는 연산(*, /, &, &&)이 합에 해당하는 연산(+, -, ^, |, ||)보다 우선순위가 높다. C 연산자 중에서 단항 연산자는 모두 우측에서 좌측으로 결합(우측 결합)한다. 이항 연산자들 중에서 우측 결합인 연산자는 대입 연산자(누적대입 연산자 포함) 뿐이다. 삼항 연산자인 ?:도 우측 결합이다. 나머지 연산자들은 모두 좌측에서 우측으로 결합(좌측 결합)한다.
요약(1/2) 부수효과 대입연산자 누적대입 연산자 증감연산자 ++, -- 값을 돌려주는 것 외에 부수적으로 다른 것을 변경시키는 효과 대입연산자, 증감연산자들은 부수효과를 발생시킨다. 대입연산자 변수에 값을 대입함 변수에 값을 저장함 누적대입 연산자 (a = a ◎ (식))인 특수한 경우에는 (a ◎= 식)으로 사용할 수 있음 증감연산자 ++, -- 변수의 값을 1 증가시키거나(증가연산), 1 감소시킴(감소연산) 전치, 후치 여부에 따라 돌려주는 값이 다름
요약(2/2) 조건연산자 ?: 괄호를 포함하는 연산자 우선순위와 결합순서 계산순서 주의사항 C의 유일한 3항연산자 조건의 참, 거짓에 따라 돌려주는 값이 다름 단락회로 계산을 수행함 괄호를 포함하는 연산자 함수호출, 형변환 연산자의 경우에만 괄호가 연산자로 사용됨 다른 경우에는 구두점(punctuation symbol) 우선순위와 결합순서 "계산하여 비교한 뒤, 판단하여 저장한다" 단항, 대입, 조건 연산자는 우측에서 좌측으로 결합 계산순서 주의사항 괄호, 우선순위, 결합순서 등은 연산자와 피연산자의 관계를 명시할 뿐, 계산순서를 명시하는 것은 아님(&&, ||, ?:는 예외)
프로그래밍 실습
▶ 프로그래밍 실습 1 체질량지수(BMI: body mass index)를 계산하여 이에 따라 비만 여부를 판별하는 프로그램을 작성하라. 체질량지수는 다음 공식(단위: kg, cm)에 의해 계산한다. 몸무게와 키를 입력으로 받아 BMI를 출력하고 비만도를 판정하는 프로그램을 작성하라.
▶ 프로그래밍 실습 2 근의 공식에 따라 이차방정식의 두 근의 근사값을 구하는 프로그램을 작성하라. 이차방정식 ax2+bx+c = 0을 입력받기 위해 이차방정식의 계수 a, b, c를 입력 받는다. 이차방정식의 계수는 float 타입으로 주어지며 a는 0이 아니라고 가정한다. 이차방정식의 근의 공식은 다음 식으로 주어진다. 근의 공식에서 제곱근을 구하기 위해서는 라이브러리 함수 sqrt를 이용하라. 예를 들어, 2의 제곱근은 sqrt(2.0)으로 구할 수 있다. 라이브러리 함수 sqrt를 사용하기 위해서는 헤더파일 <math.h>를 #include해야 한다. 실근이 하나인 경우에는 하나만 출력하고 실근이 두 개인 경우에는 두 근 중 작은 근을 먼저 출력해야 하며 실근이 없는 경우에는 ‘근이 없음’이라고 출력해야 한다.