Assignment Operators 대입 연산자
i = i + 2
는 i += 2
와 같다.
이렇게 하나의 연산자로 표현하는 것은 +
뿐만이 아니다.
+ - * / % << >> & ^ |
등의 연산자 모두 =
과 결합해서 하나의 대입연산자로 표현가능하다.
즉 expr1 op= expr2
는 expr1 = expr1 op expr2
와같다.
대입연산자의 범위에 주의해야한다.
x *= y + 1
x = x * (y + 1) // 위의 표기와 같은 의미이다.
x = x * y + 1 // 이것이 아니다.
assignment operator는 코드를 간결하게하고 이해하기 쉽게 만들어준다.
while((c = getchar()) != EOF)
와 같은 표현을 기억할 것이다. 조건문 안에 들어있는 assignment operator에 += *=
등의 assignment operator를 넣을 수 있다.
Conditional Expressions 조건 표현식 - 삼항 연산자 (C언어 코드를 읽는 것에 한해서 매우매우매우 중요)
if (a>b)
z = a;
else
z = b;
이걸 삼항연산자를 통해 하나의 식으로 표현할 수 있다! 삼항 연산자 ?:
를 이용하면
z = (a > b) ? a : b
라고 작성하면 된다.
(exp1) ? exp2 : exp3
에서 exp1이 계산되서 참이면 exp2이 반환되고, 아니면 exp3이 반환된다. 이때 exp2, exp3의 자료형이 다르면 conversion rule에 따라서 자료형이 변환된다. 예를 들어서
(n > 0 ) ? flaot : int
이런 상황이면 int는 float으로 변환된다. 조건문이 맞고 틀리고에 관계없이.
삼항연산자를 이용하면 코드를 간결하게 쓸 수 있다. 예를들면
for(i = 0; i < n; i++)
printf("%6d%c", a[i], (i%10==9 || i==n-1) ? '\n' : ' ');
// %c 부분이 (i%10==9 || i==n-1) ? '\n' : ' '...의 반환값으로 처리된다.
Precedence and Order of Evaluation 연산의 우선순위와 연산 순서
연산우선순위 이미지
C언어는 && || ?: ,(왼쪽에서 오른쪽으로 연산한다.)
등의 연산을 제외하면, 연산자의 피연산자가 계산되는 순서를 지정하지 않는다. 이에따라, x = f() + g()
는 f먼저 계산될지 g먼저 계산될지 모른다. 따라서 f 또는 g가 종속 변수를 변경하면 계산 순서가 달라질 수 있다. 중간 변수를 도입해 계산 순서가 특정되게 할 수도 있다.
비슷한 예시로,
printf("%d %d\n", ++n, power(2,n));
이 코드와
++n
printf("%d %d\n", n, power(2,n));
이 코드는 다르다.
첫 번째 코드는 컴파일러에 따라서 연산의 순서가 달라진다. power()의 호출 전에 n이 증가할 수도 있고 아닐 수도 있다는 것이다.
반면 두 번째 코드는 power()호출 전에 n이 증가하도록 특정한다.
함수 호출, nested된 대입문, 증감연산자는 연산결과 외의 추가 효과가 있다.
그리고 이는 표현식의 연산 순서에 영향을 준다.
int i = 0;
int a[5];
a[i] = i++; // undefined
이 경우 subscript인 i가 old한 것인가 new한 것인가 문제가 된다.
C 표준 문서에서 이런 상황에서의 연산순서는 정의되어있지 않기에, 이런 표현식은 지양해야한다.
결론 : 연산 순서를 확정할 수 없는 표현식을 적지 마라.
Sequence Point 시퀀스 포인트
시퀀스 포인트의 정의를 살펴보자..
A sequence point defines any point in a computer program's execution at which it is guaranteed that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed. They are often mentioned in reference to C and C++, because they are a core concept for determining the validity and, if valid, the possible results of expressions. Adding more sequence points is sometimes necessary to make an expression defined and to ensure a single valid order of evaluation. (출처 : https://en.wikipedia.org/wiki/Sequence_point)
시퀀스 포인트는 시퀀스 포인트 전의 프로그램의 동작이 모든 side effect를 마쳤음을 보장하고, 더 이상의 side effect가 없음을 보장하는 시점을 얘기한다.
int i = 0;
i = i++; // undefined
이 코드는 연산의 순서만이 문제가 아니라, 시퀀스 포인트의 문제도 있다.
한 시퀀스 포인트내에서 변수는 단 한번만 바뀌어야한다.
그런데 이 코드는 단순히 연산자 순서로 보면, i가 0이 대입됐다가, 또 1이 대입되는 일이 발생한다.
이렇게 정의되지 않은 표현식을 undefined behavior라고 한다.
참고할만한 사이트
아래는 대입연산자에 대한 연산순서 글
https://stackoverflow.com/questions/19897759/nested-assignment-statements-and-side-effects
아래는 sequence point에 관한 글
https://en.wikipedia.org/wiki/Sequence_point
https://dojang.io/mod/page/view.php?id=757