Quick Syntax
C의 식은 값을 만드는 표현식이고, 연산자는 그 값을 계산하는 방법입니다. 종류를 먼저 구분하고, 식이 어떻게 묶이고 언제 평가되는지를 따로 보면 실수가 줄어듭니다.
c
#include <stddef.h>
/* 산술: 정수끼리 나누면 소수점 이하는 버린다. */
int total = 7;
int count = 2;
double ratio = (double)total / count;
/* 논리: 왼쪽이 거짓이면 오른쪽을 평가하지 않는다. */
int value = 1;
int *ptr = &value;
if (ptr != NULL && *ptr > 0) {
value = *ptr;
}
/* 비트: 비교하려는 mask 식 전체를 괄호로 묶는다. */
enum { MASK = 0x04u };
unsigned flags = 0u;
int no_flags = ((flags & MASK) == 0u);계산 결과가 필요한지, 조건의 참·거짓이 필요한지, 비트 패턴을 바꾸는지부터 나눕니다. =와 ==, 우선순위와 실제 평가 순서는 서로 다른 문제입니다.
문법
C에서 자주 다시 보는 연산자 그룹은 산술, 비교, 논리, 비트, 대입, 증감, 조건 연산자, sizeof와 쉼표 연산자입니다.
c
int a = 7;
int b = 2;
int x = 5;
int quotient = a / b; // 정수끼리는 소수 부분을 버림
double result = (double)a / b; // 나누기 전에 실수로 변환
int before = x++; // before에 이전 x를 넣고 x를 증가
int after = ++x; // x를 증가한 뒤 after에 넣음
int larger = (a > b) ? a : b;&&와 ||는 왼쪽만으로 결과가 정해지면 오른쪽을 평가하지 않습니다. 그래서 NULL 확인을 왼쪽에 둔 뒤 역참조하는 패턴이 성립합니다.
식 해석
우선순위는 연산자를 어떻게 묶을지 정할 뿐, 피연산자를 어떤 순서로 평가할지 보장하지 않습니다.
c
enum { MASK = 0x04u };
unsigned flags = 0u;
int wrong = flags & MASK == 0; // flags & (MASK == 0)
int no_flags = ((flags & MASK) == 0u);첫 식은 보통 기대하는 mask 검사가 아닙니다. 비교 연산이 &보다 먼저 묶이므로, bitmask·비교·논리가 함께 나오면 괄호로 의도를 적습니다.
c
/* i = i++ + 1; */ // 한 객체의 수정과 사용이 얽혀 정의되지 않은 동작증감, 대입, 함수 호출을 한 식에 몰아넣으면 우선순위를 외워도 안전하지 않습니다. 값을 갱신하는 문장과 값을 사용하는 문장을 나눕니다.
경계와 실수
=는 대입이고==는 비교입니다. 조건식에서 대입이 의도라면 괄호를 써서 의도를 드러냅니다.- 0으로 나누면 안 됩니다. 정수 나눗셈은 범위 경계도 있으므로 외부 입력의 분모는 먼저 검사합니다.
%는 정수에만 사용합니다. 실수 나머지는 별도 함수와 규칙을 확인합니다.- signed와 unsigned를 섞으면 비교 전에 변환이 일어나므로, 음수를 포함할 수 있는 값은 타입을 먼저 맞춥니다.
- 비트 연산의 세부 규칙은 비트 연산 카드에서, 배열 길이는 sizeof 카드에서 이어서 확인합니다.
참고 링크
2 sources