Ch 04. 연산자 - 01. 산술 연산자 사용의 주의점

2025. 3. 29. 16:36Programming Language/C++

반응형

기본적인 내용은 모든 언어에서 비슷하기에 주의 해야할 점과 키워드를 보고 넘어가자.

 

주의점

이런 코드가 있다고 한다면 각 위치별로 결과를 예상했을때 

이런 식으로 출력될것을 기대했다.

실행시켜보면

결과가 예상과 다르게 출력되는 부분이 있다.

왜 그럴까? 

인터넷에 C++ shell로 검색해서

https://cpp.sh/

 

C++ Shell

 

cpp.sh

코드를 복사해온 다음에 여기 삽입해서 실행해보면

이 결과는 우리가 예상한 대로 된 것을 볼 수 있다.

근데 잘 보면 

한 표현식 안에서 같은 변수를 순서없이 여러번 수정했다! 라고 경고를 표출시켜준다.

음..? 

우리가 따로 순서를 지정해줘야하나..? 라고 생각이 든다.

 

근데 확인해보면 

이 부분 처럼 하나의 변수에 대한 두가지 수정이 동시에 일어난다면 C++에서는 수행의 순서가 정의 되지 않는다.

이런 경우는 정의되지 않은 동작(undefined behavior)에 해당할 수 있다.

결과적으로 컴파일러는 어떤걸 먼저 수행해야 할지 보장하지 않기에 컴파일러에 따라 ++n1을 먼저하기도, n1++을 먼저 수행하기도 할 수 있다는 말이다.

 

그래서 항상 연산을 분리해서 명확하게 순서를 보장해주는 것이 좋다.

예를 들면 

++n1;
int temp = n1 + n1++;
std::cout << temp << std::endl;

라던가

int a = ++n1;
int b = n1++;
std::cout << a + b << std::endl;

이런식으로 

 

Sequence Point

sequence point앞의 연산이 반드시 끝나고 나서, 다음 연산이 시작되는 지점으로 변수의 값 변경이나 함수 호출 등의 효과가 확실히 일어난 후 다음으로 넘어가는 지점을 말한다.

 

이 squence point가 왜 필요할까?

만약 하나의 표현식 안에 같은 변수에 여러번 접근하거나 수정할 때 sequence point가 없다면 순서가 불명확하기에 정의되지 않은 동작(undefined behavior)이 발생할 수 있는데 sequence point가 있다면 순서가 보장되므로 안전하게 연산이 수행될 수 있다.

 

위에서 봤던 연산처럼

int i = 1;
int x = i++ + ++i;  // undefined behavior (순서 보장 안 됨)

두가지 연산이 한번에 수행된다면 둘 중 어느 것이 먼저 실행될지 컴파일러가 보장하지 않는다.

 

그럼 sequence point가 추가되어 순서가 명확하다는건 어떤 상황을 이야기할까

int i = 1;
i++;
printf("%d\n", i); // 안전 — i가 증가한 뒤에 printf 호출됨

이렇게 되는 상황이다.

 

아니 그럼 sequence point는 구체적으로 뭘 말하는 걸까?

sequence point는 

sequence point 설명
; ( 세미 콜론 ) 문장의 끝(하나의 문장이 끝나면 그 안의 연산은 모두 완료 된다)
&&, ` 논리 AND 연산자는 단락 평가(short-circuit evaluation)를 하기에 sequence point가 있는 것처럼 왼쪽 피연산자의 평가가 끝나야만 오른쪽을 평가하고 이렇게 왼쪽 → 오른쪽 평가에 대한 순서가 보장된다.
함수 호출 함수 호출 전에 모든 인자가 계산 완료되어야 함
, 연산자 (콤마) 앞의 연산이 끝나야 다음 연산 수행

을 말한다.

 

C++11 이후 표준에서는 "sequence point"라는 용어 대신
"sequenced before", "unsequenced", "indeterminately sequenced" 같은 개념으로 나누는데 이는 아래 표에 정리해뒀다.

종류 설명 예시
sequenced before A가 B보다 반드시 먼저 실행됨 a++; std::cout << a;
unsequenced A와 B 중 어느 쪽이 먼저 실행될지 모름 a + ++a
indeterminately sequenced A와 B의 순서는 정해지지 않았지만, 동시에 실행되진 않음 f1() + f2()

 

이 내용은 조금 더 들어가면 깊이 볼 부분은 있지만 이것 또한 너무 깊어지면 진도가 안나가기에 일단 이런게 있다 정도만 이해하고 넘어가도록 하자.

 

결론은 같은 변수에 여러 번 접근(읽기/쓰기)하는 연산은 반드시 서로 sequence point로 분리해라 라는 것이다.

반응형

'Programming Language > C++' 카테고리의 다른 글

Ch 04. 연산자 - 03. 논리 연산자  (0) 2025.03.29
Ch 04. 연산자 - 02. 비교&관계 연산자  (0) 2025.03.29
Ch 03. 입출력 - 03. cin  (0) 2025.03.29
Ch 03. 입출력 - 03. cout  (0) 2025.03.26
Ch 03. 입출력 - 02. scanf  (0) 2025.03.25