산술연산자는 단항연산자(Unary)와 이항연산자(Binary)가 있다. 단항연산자는 숫자의 부호를 나타내는 것이고, 이항연산자에는 덧셈, 뺼셈, 곱셈, 나누기, 나머지구하기 등이 있다.
산술연산자를 사용할 때 조심해야하는 것은 우리가 일반적으로 아는 산수와는 조금 다르다는 점이다. 그리고 0으로 나누는 등의 정의되지 않는 행위(undefined behavior)를 하지 않도록 조심해야한다. 그 밖에도 구현-정의행위(Implementation-Defined Behavior)에 유의해야한다.
구현-정의행위
/나 %의 피연산자에 음수가 들어가는 경우 계산값이 정확하게 예상되지 않는것이 그 예시다. 이것은 C의 결함이 아니다. 각 소프트웨어가 컴파일, 링크, 실행을 위해서 선택할 수 있도록 의도적으로 여지를 남겨놓은 것이다. 하지만 이런방식으로 프로그램을 작성하는 것을 지양하는 것이 최선이라고 말할 수 있겠다. C표준은 구현-정의행위에 대해 문서화 할 것을 요구하고 있다.
산술 연산자도 우선순위가 있다. 단항연산자가 우선이고 그 다음이 곱셈류 이항연산자, 마지막이 덧셈류 이항연산자다. 이항연산자들은 좌항결합적이고, 단항연산자들은 우항결합적이다.
= 이거다. 할 말이 없다. 이것은 우항결합적이다.
부-작용(Side Effects) 에 대하여
일반적으로 우리는 연산자가 피연산자 자체를 변화시킬것이라고 기대하지 않는다. 그러나 단순할당과 같은 경우 피연산자를 변화시킨다. 우리는 이것을 부-작용이라고 부른다.
아래 예시와 같은 코드는 버그가 일어날 가능성이 매우 높다.
int i = 1;
k = i + (j = 1);
이걸 임베디드 할당이라고 부르기도 한다.
할당연산자는 L-Value를 필요로 한다. 여기에는 변수만 들어갈 수 있다. 상수, 표현식 같은건 못들어간다.
복잡한 설명보다는 예시가 직관적이다.
i += 1;
여기서 주의해야하는건 i += 1;과 i = i + 1;은 엄연히 다르다. 복합할당 연산자는 단순할당과 마찬가지로 우항결합적이다.
백문이 불여알견 prefix 의 경우와 postfix 의 경우를 보여주겠다.
i++;
++i;
전자는 i가 호출된 후 1증가한다. 후자는 1증가한 뒤 i가 호출된다. postfix 의 경우, 호출된 뒤 언제 증가하는지 궁금할 수 있겠으나, C는 정확하게 정의하고 있지 않다. 다만 확실한 것은 다음 구문이 실행되기 전에 증가한다. --도 마찬가지다.
증가/감소 연산자는 단항연산자와 같은 우선순위를 가지고 있다.
이제 연산자들의 우선순위와 결합방식을 알고 있으니 표현식을 자유롭게 쓸 수 있다. 하지만 이런 우선순위를 다 알고 있더라도, 가독성은 별개의 문제다. ()를 적절하게 사용해주도록 하자
문제가 있다. 연산자의 우선순위와 결합방식에 대해 알더라도, 하위식을 계산하는 순서는 알 수 없다. 즉 정의되지 않은 행위(Undefined Behhavior)다. 일반적인 산수에서는 할당 연산자가 없으니 문제가 없겠으나, C에서는 부-작용을 일으키는 연산자들이 존재한다.
예를들어, 동순위의 하위식 내에 같은 변수에 대해 부-작용을 일으키는 연산자가 있는경우 어느 하위식이 먼저 계산되는지에 따라 전체 표현식의 계산값이 달라질 것이다. 일반적으로 컴파일러는 이런경우에 경고를 출력한다.
이런 문제를 해결하기 위한 좋은 방법은, 프로그래머의 의도에 따라 여러줄로 나누어서 코드를 작성하는 것이다.
이게 뭔지는 다들 알것이다. 표현식 끝에 ;을 붙여주면 된다.