1.3 후치・전치 증감 연산자

증감 연산자는 앞이나 뒤로 ++ 혹은 – 기호를 붙여 현재 값에서 1만큼 증감하는 연산자입니다.

증감 연산자가 변수 앞에 있으면 전치 연산자, 뒤에 있으면 후치 연산자입니다. 전치・후치 연산은 대입 연산을 기준으로 각각 전후 증감이 일어납니다.

사용법을 살펴보겠습니다.

#include <stdio.h>

int main(void) {
	int a = 0;
	int b = 0;
	int c = 0;
	int d = 0;
	
	printf("++a : 원래값 %d, ", a);
	printf("대입 연산 전 %d, ", ++a);
	printf("대입 연산 후 %d\n", a);
	
	printf("b++ : 원래값 %d, ", b);
	printf("대입 연산 전 %d, ", b++);
	printf("대입 연산 후 %d\n", b);
	
	printf("--c : 원래값 %d, ", c);
	printf("대입 연산 전 %d, ", --c);
	printf("대입 연산 후 %d\n", c);
	
	printf("d-- : 원래값 %d, ", d);
	printf("대입 연산 전 %d, ", d--);
	printf("대입 연산 후 %d\n", d);
	
	return 0;
}

[결과]

++a : 원래값 0, 대입 연산 전 1, 대입 연산 후 1
b++ : 원래값 0, 대입 연산 전 0, 대입 연산 후 1
--c : 원래값 0, 대입 연산 전 -1, 대입 연산 후 -1
d-- : 원래값 0, 대입 연산 전 0, 대입 연산 후 -1

초깃값이 0인 변수 a, b, c, d로 전치・후치 연산자의 동작을 살펴봤습니다.

전치 연산은 대입 연산이 적용되기 전에 자신의 값을 변화시키는 반면, 후치 연산자는 대입 연산이 끝난 이후에 자신의 값을 변화시킵니다. 그래서 ++a와 –c는 자신의 값을 1 증감하고 나서 대입연산을 수행합니다. b++와 d–는 대입 연산을 완료한 후에 자신의 값을 1 증감합니다.

증감 연산자가 앞에 있으면 먼저, 뒤에 있으면 나중에 증감된다고 알아두시면 됩니다.

반복문인 for문과 while문에서 특히 자주 쓰입니다. 반복문에서 사용은 해당 반복문에서 알아보겠습니다. 자주 쓰는 연산이므로 조금 어렵더라도 알아두는 게 좋습니다.

제갈량의 동남풍 : +++a는 무슨 뜻일까?

+++라는 연산자는 없다.

그러므로 컴파일러는 +(++)이나 (++)+이나, (+)(+)(+)으로 해석할 것입니다.

일단 어떤 결과를 내는지 코드를 작성해 알아봅시다.


#include <stdio.h>

int main(void) {

	int a = 0;

	

	printf("%d", +++a);

	return 0;

}

[결과]

Compilation error	#stdin compilation error #stdout 0s 9424KB

prog.c: In function 'main':

prog.c:6:15: error: lvalue required as increment operand

  printf("%d", +++a);

               ^~

‘lvalue required as increment operand’라는 출력을 내려 컴파일 에러가 발생했습니다. lvalue가 필요하다는 뜻입니다.

그렇다면 lvalue는 무엇인가? left value의 조합이라고 알려져 있습니다. 즉 우리말로 좌변입니다. 연산의 결과가 대입되는 곳, 그곳이 바로 좌변입니다. 예를 들어 변수 a에 1을 더하는 코드는 다음과 같습니다.

a = 1;

위 코드에서 a는 좌측에 있으니 좌변입니다. 1은 우측에 있으니 우변 즉, rvalue입니다.

여기에서 끝나면 참 좋은데 프로그래밍이 그리 간단한 리가 없습니다. 아래 코드를 보겠습니다.

++a; 

여기서 lvalue는 무엇일까요?

연산 결과가 대입되는 곳, 바로 a입니다. 그런데 a는 ++ 연산자의 왼쪽에 있나요? 아닙니다. 오른쪽에 있습니다.

물론 위 식을 a = a +1;이라고 해서 해석 a가 lvalue라고 생각할 수 있습니다. 맞는 말씀이지만, lvalue를 좌변, rvalue를 우변으로만 해석하면 그 개념을 제대로 이해하는 것이 아니라는 말씀을 드리고 싶습니다.

lvalue는 연산 결과가 대입되는 피연자, 즉 변수이어야 합니다. 아래 코드를 보겠습니다.

1 = a;

위 코드는 컴파일하면 보나마나 컴파일 에러가 납니다.

대입 연산의 결과가 되입될 피연산자에 상수 1이 있기 때문입니다.

lvalue는 반드시 변수이어야 합니다. 그렇다면 rvalue는 상수와 변수 모두 상관 없지 않나 싶을 겁니다. 대입 연산자 입장에서 대입해야 하는 시점에 rvalue는 상수로 취급됩니다. 상수를 피연산자인 변수에 넣는다는 거죠.

++, – 연산자는 다음과 같이 lvalue만 취합니다.

++a, a++;
--a, a--;

그래서 lvalue의 l을 locate 즉 메모리에 위치를 가진 값이라고 해석하는 사람도 있지만 공식적인 견해는 아닙니다.

그럼 +++a를 해석해봅시다.

C 언어 연산자 우선 순위에 의하면 증감연산자는 덧셈 연산자보다 우선 순위가 높습니다. 그리고 연산은 죄측에서 우측 순서입니다.

그런데 +++a에서 처음에 오는 연산자를 +로 봐야 할까요? ++로 봐야할까요?

+로 봤을 때, 그다음은 +연산일까요? ++ 연산일까요?

처음은 +이고 그다음은 ++이지 않을까?

네 그럴 수도 있습니다.

그런데 C 언어는 느슨한 스펙이고 이에 대한 해석 방법이 규정되어 있지 않습니다. 따라서 해석 방법은 컴파일러마다 다를 수 있습니다. 우리가 사용한 컴파일러는 이 구문을 해석하지 못한 겁니다.

왜냐고요? 규정되지 않으니까요!

왜 규정 되지 않았냐고요?

C 언어는 느슨한 스펙이고…