본문 바로가기

C/Study

[C] 연산자 우선순위 문제

반응형

질문 제목

||연산과 &&연산

질문 요약

#include<stdio.h>

int main()
{
	int x,y,z,k;

	x = 1;
	y = 2;
	z = 3;

	k = ++x || ++y && ++z;

	printf("%d %d %d %d\n",k,x,y,z);

	return 0;
}

// 결과 값 : 1 2 2 3

 

질문 내용

결과값이 왜 이렇게 나오는 거죠??

설명좀 부탁드립니다.

설명

연산자 우선순위 문제인데...

일단 C언어의 연산자 우선순위는 다음과 같다.

C언어 연산자 우선순위 바로가기!!!

그리고 이 문제를 알기 위해서는 하나를 더 알아야 하는데...

컴파일러마다 다를수도 있지만 Visual Studio에서는 앞 조건만 봐서 무조건 결과가 참이 나오면 뒷 부분은 연산이 되지 않는다...

무슨 얘기인가 하면 x = 1, y = 1, z = 1 이 있다고 하고 if ( ++x || ++y || ++z ) 이렇게 if문이 있으면 맨 앞 ++x를 보면 참이되고

|| 연산자에 의해서 뒷 부분에 어떠한 값이 나와도 참이된다 그럼 ++y, ++z는 아예 분석조차 되지 않는다.

따라서 저 if문 다음에 x, y, z를 출력해 보면 x는 1이 증가해서 2가 되어 있지만 y, z는 그대로 1인것을 확인할 수 있다.

위에서 설명한 것을 먼저 파악하고 계속해서 문제를 보면

k = ++x || ++y && ++z; 이 라인에서 ++x 만 증가하고 y와 z는 그대로라고 생각할 수 있다.

(k의 값은 연산 결과가 참이기 때문에 1이 들어갈 것이라고 짐작할 수 있다.)

그럼 결과가 1, 2, 2, 3이 맞다.

그러나! 여기서 연산자 우선순위를 다시 한번 확인해보자... 분명히 || 보다 &&가 더 빠르다!!!

그럼 y와 z를 먼저 비교하고 다음으로 x와 비교하게 되기 때문에 당연히 y와 z도 증가되어야 하는데

결과는 그게 아니다... 그럼 연산자 우선순위가 잘못된 것인가? 그것도 아니다.

정답은 컴파일러에 있다.

#include <stdio.h>

int main()
{
	int x = 0, y = 0, z = 0, k = 0;

	x = 1;
	y = 1;
	z = 1;

	k = (++x || (++y && ++z));

	printf("k[%d] x[%d] y[%d] z[%d]\n", k, x, y, z);

	return 0;
}

 

문제와 똑같은 코드인데 ()만 추가했다. ()는 우선순위가 절대적으로 빠르기 때문에 ()를 추가해서 결과를 확인해 본 것이다.

위 코드를 실행해보면 연산자 우선순위가 제일 높은 ()로 묶었음에도 불구하고 같은 결과값이 나오는데

이걸로 유추해 볼때 뒤 ++y && ++z는 아예 분석조차 안된다고 생각할 수 있다.

즉 컴파일러가 코드 분석을 할 때 좌측에서 우측으로 분석이 되는데

++x ||를 분석하는 순간 우측은 분석할 필요도 없이 결과값이 무조건 참이 나오기 때문에

++x || 다음 구문은 해석조차 하지 않고 다음 구문으로 넘어가 버리는 것 같다.

구문 분석 단계에서 결정이 나기 때문에 연산자 우선순위는 필요가 없다.

일단 컴파일러가 구문 분석을 해야 그 이후에 연산자 우선순위를 따져 빠른 연산부터 수행을 하는데

이와같은 경우에는 아예 뒤쪽은 분석도 안하고 넘어가 버리는 것 같다.

이는 컴파일러의 컴파일 방식이므로 컴파일러마다 결과가 다르게 나올 수 있다.

확인해 본 결과 gcc와 VS2010에서는 동일한 결과가 나왔다.

컴파일이 이렇게 수행되는 이유는 컴파일 속도를 조금이라도 높게 하기 위한 것이라고 추측된다.

마지막으로 간단하게 예를 들어 설명 드리자면

k = 0 * ((256 - 36) / ((5634 % 3) + 234 / (7 * (3 + 5)))); 뭐 이러한 공식이 있다고 칠 때

컴퓨터가 푸는게 아니라 사람이 푼다고 생각했을 때 어느 사람이든 맨 앞에 0 * 를 보는 순간 뒤에 무슨

내용이 나오던지 답은 0이 될 것이기에 뒤는 보지도 않고 k = 0 이라고 할 것이다.

(물론 뒷 부분을 전부 계산하고 나서 마지막에 0과 곱해서 답을 0이라고 할 수도 있지만 시간이 걸릴것이다.)

뒤에 ()로 묶인 + 연산이 빨리 되던지 곱하기가 빨리 되던지 따윈 중요하지 않다 뒤에 연산 결과가 어떻게 나오든 결과는 0이니까...

컴파일러도 이와 마찬가지로 앞 부분만 봐서 결과가 정해지면 뒤의 내용는 구문 분석조차 하지 않고 넘어가는것 같다.

위 내용은 어디까지나 결과만을 가지고 추측한 내용이기 때문에 틀릴 수 있다.

위 내용에 틀린 부분이 있거나 정확한 이유를 아시는 분은 댓글을 통해 태글, 수정 및 지적해 주시면 감사하겠습니다.

반응형

'C > Study' 카테고리의 다른 글

컴파일과 빌드의 차이점  (0) 2024.12.21
[C] 오류와 경고의 차이점  (0) 2024.12.21
[C] C언어의 장점  (1) 2024.12.20
[C] C프로그래밍이 실행되기까지  (0) 2024.12.20
[C] __int64  (0) 2024.12.20